文件映射复制速度更快?

发布于 2024-10-22 01:02:11 字数 2273 浏览 7 评论 0原文

我使用线程和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;

我的问题出在哪里?

I made ​​an application to copy a file using thread and the method of TFileStream, but I was a little disappointed with the speed, especially when copying large files. Then I heard about the file mapping, which apparently could certainly yield a method of copying a lot faster since access to the files would be much faster.

I'm a beginner so I'm trying to, but I have not managed to copy a file via file mapping. (The file is created test2.iso but instead of doing 0ko 3GB ^ ^.)

Here is my code.

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;

Where is my problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

等风也等你 2024-10-29 01:02:11

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

首先,您使用 CreateFileMappingdwFileOffsetLow 指定 2Kb,然后将整个文件大小传递给 WriteFile。使用此映射视图,nNumberOfBytesToWrite 最多应使用 2Kb 来调用“WriteFile”。

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

[...]

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

Not that I disagree with the comments to your question, but there are two reasons that fail your code.

First is, you're specifying 2Kb for dwFileOffsetLow with CreateFileMapping but then passing the entire file size to WriteFile. With this mapping view, 'WriteFile' should be called at most with 2Kb for nNumberOfBytesToWrite.

Second is, you're not passing the starting address of your file data correct, try this:

[...]

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

[...]

BTW, the reason the code is not returning any errors is that you're not checking the return of 'WriteFile'.

烟─花易冷 2024-10-29 01:02:11

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

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

The system FileCopy does use memory mapped files. If the file is large you can watch the amount of virtual memory decrease on your system as the mapping takes place. There was a 'feature' in Windows Server recently that would use all of the available virtual RAM to build up the mapping. So... I would use FileCopy (or FileCopyEx) and let the OS decide on the best way to move the data (it is likely to know best). If you do it in a separate thread you can even do it without stopping your program - and it will be a very quick copy as most CPUs will spend most of the time buffing their nails waiting for the disk/network.

In your example shouldn't you be CreateFileMapping with PAGE_READONLY and MapViewOfFile with FILE_MAP_READ? The pointer returned (FMappingPtr) should point to valid be visible in the debugger - and it should look like you file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文