我创建了一个使用线程和TFileStream方法复制文件的应用程序,但我对速度有点失望,特别是在复制大文件时。然后我听说文件映射,显然它可以产生一种更快速复制的方法,因为访问文件的速度会快得多。
我是初学者所以我正在尝试,但我还没有设法通过文件映射复制文件。 (该文件是创建test2.iso但不是做0ko 3GB ^ ^。)
这是我的代码。
procedure TForm1.Button1Click(Sender: TObject);
var
FFilehandle: THANDLE;
FFileMap: THANDLE;
FmappingPtr: pchar;
hFile2: THANDLE ;
SizeFile1,BytesWritten: DWORD ;
begin
FFilehandle := CreateFile('titan.iso',
GENERIC_WRITE OR GENERIC_READ,
FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (FFilehandle <> INVALID_HANDLE_VALUE) then
begin
FFileMap := CreateFileMapping(FFileHandle, // handle to file to map
nil, // optional security attributes
PAGE_READWRITE, // protection for mapping object
0, // high-order 32 bits of object size
2*1024, // low-order 32 bits of object size
0); //
if (FFileMap <> NULL) then
begin
FMappingPtr := MapViewOfFile(FFileMap,
FILE_MAP_WRITE,
0,
0,
0);
if Assigned(FMappingPtr) then
begin
// Manipulation de FMappingPtr
hFile2 := CreateFile('test.iso', GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile2 <> INVALID_HANDLE_VALUE) then
begin
SizeFile1 := GetFileSize(FFilehandle, NIL); // recupere taille du fichier 1
WriteFile(hFile2, Fmappingptr, SizeFile1, &BytesWritten, NIL); // Transfert la mémoire mappé dans file 2
// libere les ressources
end
else
MessageBox(0, 'Impossible de lire le fichier mappé', 'Error', 0);
UnmapViewOfFile(Fmappingptr);
CloseHandle(FFileMap);
CloseHandle(FFilehandle);
CloseHandle(hFile2);
end
else
begin
CloseHandle (FFileMap);
CloseHandle (FFileHandle);
MessageBox(0, 'Impossible de lire le fichier mappé', 'Error', 0);
end;
end
else
begin
CloseHandle (FFilemap);
MessageBox(0, 'Impossible de mappe le fichier en mémoire', 'Error', 0);
end;
end
else
MessageBox(NULL, 'Impossible d''ouvrir le fichier', 'Error', NULL);
end;
我的问题在哪里?
答案 0 :(得分:2)
系统FileCopy确实使用内存映射文件。如果文件很大,您可以在映射发生时观察系统上的虚拟内存减少量。最近Windows Server中有一个“功能”,它将使用所有可用的虚拟RAM来构建映射。所以...我会使用FileCopy(或FileCopyEx)让操作系统决定移动数据的最佳方式(它可能最了解)。如果你在一个单独的线程中执行它,你甚至可以在不停止你的程序的情况下完成它 - 而且它将是一个非常快速的副本,因为大多数CPU将花费大部分时间来修复他们的指甲等待磁盘/网络。
在您的示例中,您不应该使用PAGE_READONLY创建CreateFileMapping而使用FILE_MAP_READ创建MapViewOfFile吗?返回的指针(FMappingPtr)应指向有效在调试器中可见 - 它应该看起来像你提交。
答案 1 :(得分:2)
并非我不同意您对问题的评论,但有两个原因导致您的代码失败。
首先,您使用dwFileOffsetLow
为CreateFileMapping
指定2Kb,然后将整个文件大小传递给WriteFile
。使用此映射视图,{Write}最多应调用'WriteFile',nNumberOfBytesToWrite
为2Kb。
其次,你没有正确传递文件数据的起始地址,试试这个:
[...]
FFileMap := CreateFileMapping(FFileHandle, // handle to file to map
nil, // optional security attributes
PAGE_READWRITE, // protection for mapping object
0, // high-order 32 bits of object size
0, // low-order 32 bits of object size
0); //
if (FFileMap <> NULL) then
begin
FMappingPtr := MapViewOfFile(FFileMap,
FILE_MAP_WRITE,
0,
0,
0);
if Assigned(FMappingPtr) then
begin
// Manipulation de FMappingPtr
hFile2 := CreateFile('test.iso', GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile2 <> INVALID_HANDLE_VALUE) then
begin
SizeFile1 := GetFileSize(FFilehandle, NIL); // recupere taille du fichier 1
WriteFile(hFile2, Fmappingptr[0], SizeFile1, &BytesWritten, NIL); // Transfert la mémoire mappé dans file 2
// libere les ressources
end
[...]
顺便说一下,代码没有返回任何错误的原因是你没有检查'WriteFile'的返回。