• 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;

  • 相关阅读:
    Identity Server 4 原理和实战(完结)_建立Angular 客户端
    Identity Server 4 原理和实战(完结)_为 MVC 客户端刷新 Token
    Identity Server 4 原理和实战(完结)_Authorization Code Flow 实例
    Identity Server 4 原理和实战(完结)_Resource Owner Password Credentials 授权实例
    ASP.NET Core会议管理平台实战_2、基本概念的理解
    ASP.NET Core会议管理平台实战_汇总贴
    ASP.NET Core会议管理平台实战_1、开篇介绍
    Identity Server 4 原理和实战(完结)_建立Identity Server 4项目,Client Credentials 授权实例
    Identity Server 4 原理和实战(完结)_----选看 OpenId Connect 简介
    Identity Server 4 原理和实战(完结)_----选看 OAuth 2.0 简介(下)
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/2940625.html
Copyright © 2020-2023  润新知