gpt4 book ai didi

delphi - 如何使用 API ReadFile() WriteFile() 进行无缓冲文件传输?

转载 作者:行者123 更新时间:2023-12-03 15:07:30 26 4
gpt4 key购买 nike

问题是,当我禁用缓存(在CreateFile中设置FILE_FLAG_NO_BUFFERING)时,我必须向读写函数传递一些字节数,该字节数是512(扇区大小)。我使用 10MB 的缓冲区,一切都很好......直到最后一次缓冲区操作。最后一个缓冲区的字节数不是 512 的倍数。那么,我如何读取和写入文件的最后部分?

这是我到目前为止所写的......

procedure MarusCopyFileNoCache(SrcName,DestName:string);
const BufSize = 10485760; {10MB}
var Src,Dest:THandle;
Buffer:Pointer;
Bufs,x:integer;
AllSize:int64;
N,junk:DWord;
begin
Src:=CreateFileW(PWideChar('\\?\'+SrcName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
Dest:=CreateFileW(PWideChar('\\?\'+DestName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, 0);
try
AllSize:=MFileSize(Src); {this is my function to get the int64 file size}
Bufs:=Ceil(AllSize/BufSize);
GetMem(Buffer,BufSize);
try
for x:=1 to Bufs do begin
ReadFile(Src, Buffer^, BufSize, N, nil);
WriteFile(Dest, Buffer^, N, junk, nil);
end;
finally
FreeMem(Buffer,BufSize);
end;
finally
CloseHandle(Src);
CloseHandle(Dest);
end;
end;

最佳答案

使用FILE_FLAG_NO_BUFFERING时,您必须读取和写入完整扇区,但最后一个缓冲区将是部分扇区(ReadFile()将报告读取的字节数少于读取的字节数)全扇区大小)。当您写入最后一个缓冲区时,您仍然必须将其写入整个扇区,否则 WriteFile() 将失败。显然输出文件大小可能太大。但是,由于您确实知道所需的文件大小,因此可以使用 SetFileInformationByHandle()在写入完成后、关闭其句柄之前设置输出文件的最终大小。

例如:

type
FILE_INFO_BY_HANDLE_CLASS = (
FileBasicInfo = 0,
FileStandardInfo = 1,
FileNameInfo = 2,
FileRenameInfo = 3,
FileDispositionInfo = 4,
FileAllocationInfo = 5,
FileEndOfFileInfo = 6,
FileStreamInfo = 7,
FileCompressionInfo = 8,
FileAttributeTagInfo = 9,
FileIdBothDirectoryInfo = 10, // 0xA
FileIdBothDirectoryRestartInfo = 11, // 0xB
FileIoPriorityHintInfo = 12, // 0xC
FileRemoteProtocolInfo = 13, // 0xD
FileFullDirectoryInfo = 14, // 0xE
FileFullDirectoryRestartInfo = 15, // 0xF
FileStorageInfo = 16, // 0x10
FileAlignmentInfo = 17, // 0x11
FileIdInfo = 18, // 0x12
FileIdExtdDirectoryInfo = 19, // 0x13
FileIdExtdDirectoryRestartInfo = 20, // 0x14
MaximumFileInfoByHandlesClass);

FILE_END_OF_FILE_INFO = record
EndOfFile: LARGE_INTEGER;
end;

function SetFileInformationByHandle(
hFile: THandle;
FileInformationClass: FILE_INFO_BY_HANDLE_CLASS;
lpFileInformation: Pointer;
dwBufferSize: DWORD
): BOOL; stdcall; external 'kernel32.dll' delayed;

procedure MarcusCopyFileNoCache(SrcName, DestName: string);
const
BufSize = 10485760; {10MB}
var
Src, Dest: THandle;
Buffer: PByte;
FinalSize: Int64;
SectorSize, N, ignored: DWORD;
eof: FILE_END_OF_FILE_INFO;
begin
Src := CreateFile(PChar('\\?\'+SrcName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
if Src = INVALID_HANDLE_VALUE then RaiseLastOSError;
try
Dest := CreateFile(PChar('\\?\'+DestName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, 0);
if Dest = INVALID_HANDLE_VALUE then RaiseLastOSError;
try
try
FinalSize := 0;
SectorSize := 512; // <-- TODO: determine this dynamically at runtime
GetMem(Buffer, BufSize);
try
repeat
if not ReadFile(Src, Buffer^, BufSize, N, nil) then RaiseLastOSError;
if N = 0 then Break; // EOF reached
Inc(FinalSize, N);
// round up the number of bytes read to the next sector boundary for writing
N := (N + (SectorSize-1)) and (not (SectorSize-1));
if not WriteFile(Dest, Buffer^, N, ignored, nil) then RaiseLastOSError;
until False;
finally
FreeMem(Buffer, BufSize);
end;
// now set the final file size
eof.EndOfFile.QuadPart := FinalSize;
if not SetFileInformationByHandle(Dest, FileEndOfFileInfo, @eof, SizeOf(eof)) then RaiseLastOSError;
finally
CloseHandle(Dest);
end;
except
DeleteFile(PChar(DestName));
raise;
end;
finally
CloseHandle(Src);
end;
end;

关于delphi - 如何使用 API ReadFile() WriteFile() 进行无缓冲文件传输?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25703256/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com