Delphi中的异步文件I/O

Delphi中的异步文件I/O,delphi,asynchronous,io,Delphi,Asynchronous,Io,在此delphi.net(prism)中支持异步文件io。 Delphi(本机/VCL)也有异步文件IO类 RTL/VCL中没有为文件提供异步I/O的内置功能。顺便说一句,Delphi Prism中的支持是基于.net框架的,而不是基于语言的 您可以直接针对Win32 API编写代码(这并不有趣),也可以四处寻找该API的Delphi包装。恕我直言,我不知道异步文件I/O的任何Delphi包装器,但它们必须存在。您看到这段代码了吗 对于同步文件I/O来说,这是一个良好的开端,但就我个人而言,我会

在此delphi.net(prism)中支持异步文件io。
Delphi(本机/VCL)也有异步文件IO类

RTL/VCL中没有为文件提供异步I/O的内置功能。顺便说一句,Delphi Prism中的支持是基于.net框架的,而不是基于语言的

您可以直接针对Win32 API编写代码(这并不有趣),也可以四处寻找该API的Delphi包装。恕我直言,我不知道异步文件I/O的任何Delphi包装器,但它们必须存在。

您看到这段代码了吗

对于同步文件I/O来说,这是一个良好的开端,但就我个人而言,我会围绕标准的
TStream
类编写一个包装器,以保持与VCL/RTL的兼容性

编辑2:这个看起来也不错

我把它贴在这里,以防它从粘贴箱中消失:

unit xfile;

{$I cubix.inc}

interface

uses
  Windows,
  Messages,
  WinSock,
  SysUtils,
  Classes;

const
  MAX_BUFFER = 1024 * 32;

type
  TFileReadEvent = procedure(Sender: TObject; const Buffer; Count: Integer) of object;

  TAsyncFile = class
  private
    FHandle: THandle;
    FPosition: Cardinal;
    FReadPending: Boolean;
    FOverlapped: TOverlapped;
    FBuffer: Pointer;
    FBufferSize: Integer;
    FOnRead: TFileReadEvent;
    FEof: Boolean;
    FSize: Integer;
    function ProcessIo: Boolean;
    procedure DoOnRead(Count: Integer);
    function GetOpen: Boolean;
  public
    constructor Create(Filename: string; BufferSize: Integer = MAX_BUFFER);
    destructor Destroy; override;
    procedure BeginRead;
    procedure Seek(Position: Integer);
    procedure Close;
    property OnRead: TFileReadEvent read FOnRead write FOnRead;
    property Eof: Boolean read FEof;
    property IsOpen: Boolean read GetOpen;
    property Size: Integer read FSize;
  end;

function ProcessFiles: Boolean;

implementation

var
  Files: TList;

function ProcessFiles: Boolean;
var
  i: Integer;
  AsyncFile: TAsyncFile;
begin
  Result := False;
  for i := Files.Count - 1 downto 0 do
  begin
    AsyncFile := TAsyncFile(Files[i]);
    Result := AsyncFile.ProcessIo or Result;
  end;
end;

procedure Cleanup;
var
  i: Integer;
  AsyncFile: TAsyncFile;
begin
  for i := Files.Count - 1 downto 0 do
  begin
    AsyncFile := TAsyncFile(Files[i]);
    AsyncFile.Free;
  end;
  Files.Free;
end;

{ TAsyncFile }

constructor TAsyncFile.Create(Filename: string; BufferSize: Integer);
begin
  Files.Add(Self);
  FReadPending := False;
  FBufferSize := BufferSize;
  GetMem(FBuffer, FBufferSize);
  FillMemory(@FOverlapped, SizeOf(FOverlapped), 0);

  Cardinal(FHandle) := CreateFile(
                  PChar(Filename),         // file to open
                  GENERIC_READ,            // open for reading
                  0,                       // do not share
                  nil,                     // default security
                  OPEN_EXISTING,           // open existing
                  FILE_ATTRIBUTE_NORMAL, //or // normal file
                  //FILE_FLAG_OVERLAPPED,    // asynchronous I/O
                  0);                      // no attr. template

  FSize := FileSeek(FHandle, 0, soFromEnd);
  FileSeek(FHandle, 0, soFromBeginning);
  FPosition := 0;
end;

destructor TAsyncFile.Destroy;
begin
  Files.Remove(Self);
  CloseHandle(FHandle);
  FreeMem(FBuffer);
  inherited;
end;

function TAsyncFile.ProcessIo: Boolean;
var
  ReadCount: Cardinal;
begin  
  Result := False;  Exit;
  if not FReadPending then
  begin
    Exit;
  end;

  if GetOverlappedResult(FHandle, FOverlapped, ReadCount, False) then
  begin
    FReadPending := False;
    DoOnRead(ReadCount);
  end
  else
  begin
    case GetLastError() of
      ERROR_HANDLE_EOF:
      begin
        FReadPending := False;
        FEof := True;
      end;
      ERROR_IO_PENDING:
      begin
        FReadPending := True;
      end;
      0:
      begin
        Result := True; 
      end;
    end;
  end;
end;

procedure TAsyncFile.BeginRead;
var
  ReadResult: Boolean;
  ReadCount: Cardinal;
begin
  ReadCount := 0;
  Seek(FPosition);
  ReadResult := ReadFile(FHandle, FBuffer^, FBufferSize, ReadCount, nil);//@FOverlapped);
  if ReadResult then
  begin
    FEof := False;
    FReadPending := False;
    FPosition := FPosition + ReadCount;
    DoOnRead(ReadCount);
  end
  else
  begin
    case GetLastError() of
      ERROR_HANDLE_EOF:
      begin
        FReadPending := False;
        FEof := True;
      end;
      ERROR_IO_PENDING:
      begin
        FReadPending := True;
      end;
    end;
  end;
end;

procedure TAsyncFile.DoOnRead(Count: Integer);
begin
  if Assigned(FOnRead) then
  begin
    FOnRead(Self, FBuffer^, Count);
  end;
end;

function TAsyncFile.GetOpen: Boolean;
begin
  Result := Integer(FHandle) >= 0;
end;

procedure TAsyncFile.Close;
begin
  FileClose(FHandle);
end;

procedure TAsyncFile.Seek(Position: Integer);
begin
  FPosition := Position;
  FileSeek(FHandle, Position, soFromBeginning);
end;

initialization
  Files := Tlist.Create;

finalization
  Cleanup;

end.

对于VC++来说,有一个可以很容易地移植到Delphi的东西:——但我的问题是为什么要麻烦。原始Win32 API并不难处理,您需要一个类包装器。相关/相关:在上面的文章中是基于事件的(ReadDone函数),但dstream不是基于事件的,Read和ReadAsync的参数是sameI给了您两个代码,只要根据您的需要调整它们,而不是抱怨和要求现成的解决方案。@Pateman我当然不会从您问题中的代码开始。它的质量很低。