WriteFileFromBuffer

function WriteFileFromBuffer(const AFileName: string; AFileSize: Cardinal; var AData; AIsAppend: Boolean = False): Boolean;
type
PTQWord = ^TQWord;
TQWord = packed record
    case Boolean of
      False: (QWORD: Int64);
      True: (LODWORD: DWORD; HIDWORD: DWORD);
end;

var
DriveName: string;
MappingName: string;
DiskFreeSize: Int64;
FileHandle: THandle;
MappingHandle: THandle;
IsNewFile, IsMapping: Boolean;
FindData: TWin32FindData;
TheCreationTime: TFileTime;
FileAttrs: DWORD;
OpenMode: DWORD;
ExistsSize, ThisSize: TQWord;
PFileData, P, PSource: Pointer;
Segment: Cardinal;
Offset: Cardinal;
OffsetSize: Cardinal;
CommitSize: Cardinal;

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

begin
Result := False;
if PPointer(@AData)^ = nil then Exit;
if AFileSize = 0 then Exit;

try
    PFileData := nil;
    MappingHandle := 0;
    FileHandle := INVALID_HANDLE_VALUE;

    ThisSize.QWORD := 0;
    ExistsSize.QWORD := 0;

    DriveName := ExtractFileDrive(AFileName);
    if DriveName = '' then DriveName := ExtractFileDrive(ParamStr(0));
    DiskFreeSize := DiskFree(Byte(UpCase(DriveName[1])) - $40);
    FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData);
    if FileHandle = INVALID_HANDLE_VALUE then
    begin
      if DiskFreeSize < AFileSize then Exit;
      OpenMode := CREATE_NEW;
      IsNewFile := True;
      ThisSize.QWORD := AFileSize;

      FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess, Const_FileShare, nil, OpenMode, 0, 0);
      if FileHandle = INVALID_HANDLE_VALUE then Exit;

      try
        CriticalSectionLock;
        Windows.SetFilePointer(FileHandle, ThisSize.LODWORD, @ThisSize.HIDWORD, FILE_BEGIN);
        Windows.SetEndOfFile(FileHandle);
      finally
        CriticalSectionUnlock;
      end;
      Windows.CloseHandle(FileHandle);

      FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData);
      if FileHandle = INVALID_HANDLE_VALUE then Exit;
    end
    else
      IsNewFile := False;

    Windows.FindClose(FileHandle);

    TheCreationTime := FindData.ftCreationTime;
    MappingName := GetFileNameExcludeExt(AFileName) + Format('_%.8x%.8x', [TheCreationTime.dwHighDateTime, TheCreationTime.dwLowDateTime]);
    if AIsAppend then
    begin
      if not IsNewFile then
      begin
        ExistsSize.HIDWORD := FindData.nFileSizeHigh;
        ExistsSize.LODWORD := FindData.nFileSizeLow;
        ThisSize.QWORD := AFileSize + ExistsSize.QWORD;
      end
      else
        ThisSize.QWORD := AFileSize;
      if DiskFreeSize < (AFileSize + ExistsSize.QWORD) then Exit;
      OpenMode := OPEN_ALWAYS
    end
    else
    begin
      if DiskFreeSize < AFileSize then Exit;
      OpenMode := TRUNCATE_EXISTING;
      ThisSize.QWORD := AFileSize;
    end;

    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;

    try
      FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess, Const_FileShare, nil, OpenMode, 0, 0);
      if FileHandle = INVALID_HANDLE_VALUE then Exit;

      MappingHandle := Windows.OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(MappingName));
      IsMapping := MappingHandle <> 0;
      if not IsMapping then
      begin
        MappingHandle := Windows.CreateFileMapping(FileHandle, nil, PAGE_READWRITE or SEC_RESERVE, ThisSize.HIDWORD,
          ((((ThisSize.LODWORD and $FFFF0000) shr 16) + 1) shl 16), PChar(MappingName));
        if (MappingHandle = 0) or (Windows.GetLastError <> ERROR_SUCCESS) then Exit;
      end;

      PSource := PPointer(@AData)^;
      PFileData := nil;
      Segment := 0;
      if AIsAppend then
      begin
        Offset := ExistsSize.LODWORD and $0000FFFF;
        if Offset > 0 then
        begin
          Segment := ExistsSize.LODWORD and $FFFF0000;
          if ((Offset + AFileSize) and $FFFF0000) > 0 then
          begin
            PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, $00010000);
            if PFileData = nil then Exit;
            CommitSize := $00010000;
            OffsetSize := ((Offset xor $FFFFFFFF) and $0000FFFF) + 1
          end
          else
          begin
            OffsetSize := (((Offset + AFileSize) shr 12) + 1) shl 12;
            PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, OffsetSize);
            if PFileData = nil then Exit;
            CommitSize := OffsetSize;
            OffsetSize := AFileSize;
          end;
          P := Pointer(DWORD(PFileData) + Offset);
          if not MoveDataTo(PSource, P, OffsetSize) then Exit;
          Windows.UnmapViewOfFile(PFileData);
          PSource := Pointer(DWORD(PSource) + OffsetSize );
          Dec(AFileSize, OffsetSize);
          if AFileSize > 0 then Segment := ((Segment shr 16) + 1) shl 16;
        end;
      end;

      while AFileSize <> 0 do
      begin
        if AFileSize and $FFFF0000 > 0 then
        begin
          PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, $00010000);
          if PFileData = nil then Exit;
          CommitSize := $00010000;
          if not MoveDataTo(PSource, PFileData, $00010000) then Exit;
          Windows.UnmapViewOfFile(PFileData);
          PSource := Pointer(DWORD(PSource) + $00010000);
          Dec(AFileSize, $00010000);
          if AFileSize > 0 then Segment := ((Segment shr 16) + 1) shl 16;
        end
        else
        begin
          PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, AFileSize);
          if PFileData = nil then Exit;
          CommitSize := ((AFileSize shr 12) + 1) shl 12;
          if not MoveDataTo(PSource, PFileData, AFileSize) then Exit;
          Windows.UnmapViewOfFile(PFileData);
          Dec(AFileSize, AFileSize);
        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
      begin
        if Result then
        begin
          try
            CriticalSectionLock;
            Windows.SetFilePointer(FileHandle, ThisSize.LODWORD, @ThisSize.HIDWORD, FILE_BEGIN);
            Windows.SetEndOfFile(FileHandle);
          finally
            CriticalSectionUnlock;
          end;
        end;
        Windows.CloseHandle(FileHandle);
      end;
    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);
      Exit;
    end;
end;
end;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值