WriteFileFromBuffer

    技术2022-05-20  44

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

    varDriveName: 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;

    beginResult := 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)