现在的位置: 首页 > 综合 > 正文

ReadFileToBuffer

2012年10月04日 ⁄ 综合 ⁄ 共 4153字 ⁄ 字号 评论关闭

function ReadFileToBuffer(const AFileName: string; var AFileSize: Cardinal; var AData): Boolean;
var
FileHandle: THandle;
MappingHandle: THandle;
FindData: TWin32FindData;
MappingName: string;
TheCreationTime: TFileTime;
FileAttrs: DWORD;
ThisSize: Cardinal;
CommitSize: Cardinal;
Segment: Cardinal;
PFileData, PDest: Pointer;

procedure ReleaseMemory;
begin
    Windows.VirtualFree(PDest, 0, MEM_RELEASE);
    PPointer(@AData)^ := nil;
    AFileSize := 0;
end;

function MoveDataTo(ASource, ADest: Pointer; ASize: Cardinal): Boolean;
begin
    Result := False;
    try
      CriticalSectionLock;
      try
        Windows.VirtualAlloc(PFileData, CommitSize, MEM_COMMIT, PAGE_READONLY);
        Windows.VirtualLock(PFileData, CommitSize);
        System.Move(ASource^, ADest^, ASize);
      finally
        Windows.VirtualUnlock(PFileData, CommitSize);
        Windows.VirtualFree(PFileData, CommitSize, MEM_DECOMMIT);
        CriticalSectionUnlock;
      end;
    except
      on EAccessViolation do
      begin
        Windows.VirtualUnlock(PFileData, CommitSize);
        Windows.VirtualFree(PFileData, CommitSize, MEM_DECOMMIT);
        CriticalSectionUnlock;
        ReleaseMemory;
        Exit;
      end;
    end;
    Result := True;
end;

begin
Result := False;
AFileSize := 0;
FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData);
if FileHandle = INVALID_HANDLE_VALUE then Exit;
ThisSize := FindData.nFileSizeLow;
Windows.FindClose(FileHandle);

FileAttrs := Windows.GetFileAttributes(PChar(AFileName));
if (FileAttrs and FILE_ATTRIBUTE_READONLY) <> 0 then
begin
    if not Windows.SetFileAttributes(PChar(AFileName), FileAttrs xor

FILE_ATTRIBUTE_READONLY) then Exit;
end;

if ThisSize = 0 then
begin
    Windows.DeleteFile(PChar(AFileName));
    Exit;
end;

try
    PDest := nil;
    PDest := Windows.VirtualAlloc(nil, ThisSize, MEM_COMMIT or MEM_RESERVE,

PAGE_READWRITE);

    PFileData := nil;
    AFileSize := ThisSize;
    PPointer(@AData)^ := PDest;

    CommitSize := 0;
    while CommitSize < AFileSize do
    begin
      PByte(PDest)^ := 0;
      PDest := Pointer(DWORD(PDest) + $00001000);
      Inc(CommitSize, $00001000);
    end;
    PDest := PPointer(@AData)^;

    try
      FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess,

Const_FileShare, nil, OPEN_EXISTING, 0, 0);
      if FileHandle = INVALID_HANDLE_VALUE then
      begin
        ReleaseMemory;
        Exit;
      end;

      TheCreationTime := FindData.ftCreationTime;
      MappingName := GetFileNameExcludeExt(AFileName) + Format('_%.8x%.8x',

[TheCreationTime.dwHighDateTime, TheCreationTime.dwLowDateTime]);
      MappingHandle := Windows.OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar

(MappingName));
      if not MappingHandle <> 0 then
      begin
        MappingHandle := Windows.CreateFileMapping(FileHandle, nil, PAGE_READWRITE or

SEC_RESERVE, 0, ThisSize, PChar(MappingName));
        if (MappingHandle = 0) or (Windows.GetLastError <> ERROR_SUCCESS) then
        begin
          ReleaseMemory;
          Exit;
        end;
      end;

      Segment := 0;
      while ThisSize <> 0 do
      begin
        if ThisSize and $FFFF0000 > 0 then
        begin
          PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0,

Segment, $00010000);
          if PFileData = nil then
          begin
            ReleaseMemory;
            Exit;
          end;
          if not MoveDataTo(PFileData, PDest, $00010000) then Exit;
          Windows.UnmapViewOfFile(PFileData);
          PDest := Pointer(DWORD(PDest) + $00010000);
          Segment := ((Segment shr 16) + 1) shl 16;
          Dec(ThisSize, $00010000);
        end
        else
        begin
          PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0,

Segment, ThisSize);
          if PFileData = nil then
          begin
            ReleaseMemory;
            Exit;
          end;
          if not MoveDataTo(PFileData, PDest, ThisSize) then Exit;
          Windows.UnmapViewOfFile(PFileData);
          Dec(ThisSize, ThisSize);
        end;
      end;

      PFileData := nil;
      Result := True;
    finally
      if PFileData <> nil then Windows.UnmapViewOfFile(PFileData);
      if MappingHandle <> 0 then Windows.CloseHandle(MappingHandle);
      if FileHandle <> INVALID_HANDLE_VALUE then Windows.CloseHandle(FileHandle);
    end;
except
    on Exception do
    begin
      if PFileData <> nil then Windows.UnmapViewOfFile(PFileData);
      if MappingHandle <> 0 then Windows.CloseHandle(MappingHandle);
      if FileHandle <> INVALID_HANDLE_VALUE then Windows.CloseHandle(FileHandle);
      ReleaseMemory;
      Exit;
    end
end;
end;

抱歉!评论已关闭.