2

我做了一个应用程序来使用线程和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;

我的问题在哪里?

4

2 回答 2

2

系统 FileCopy 确实使用内存映射文件。如果文件很大,您可以看到系统上的虚拟内存量随着映射的发生而减少。最近 Windows Server 中有一个“功能”可以使用所有可用的虚拟 RAM 来构建映射。所以......我会使用 FileCopy(或 FileCopyEx)并让操作系统决定移动数据的最佳方式(它可能最了解)。如果您在单独的线程中执行此操作,您甚至可以在不停止程序的情况下执行此操作 - 这将是一个非常快速的副本,因为大多数 CPU 将花费大部分时间来打磨他们的指甲等待磁盘/网络。

在您的示例中,您不应该是使用 PAGE_READONLY 的 CreateFileMapping 和使用 FILE_MAP_READ 的 MapViewOfFile 吗?返回的指针(FMappingPtr)应该指向在调试器中可见的有效 - 它应该看起来像你的文件。

于 2011-03-14T18:25:42.167 回答
2

并不是说我不同意您对问题的评论,而是有两个原因导致您的代码失败。

首先,您为dwFileOffsetLowwith指定 2Kb,CreateFileMapping然后将整个文件大小传递给WriteFile. 使用此映射视图,对于nNumberOfBytesToWrite.

其次,您没有正确传递文件数据的起始地址,请尝试以下操作:

[...]

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”的返回。

于 2011-03-14T19:19:24.990 回答