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

あなたの質問に対するコメントに同意しないわけではありませんが、コードが失敗する理由は 2 つあります。

dwFileOffsetLowまず、 with に2Kb を指定していますCreateFileMappingが、ファイル サイズ全体を に渡しますWriteFile。このマッピング ビューでは、'WriteFile' は最大 2Kb で呼び出されnNumberOfBytesToWriteます。

2つ目は、ファイルデータの開始アドレスを正しく渡していないことです。これを試してください:

[...]

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 に答える
2

システム FileCopy はメモリ マップ ファイルを使用します。ファイルが大きい場合、マッピングが行われるにつれてシステムの仮想メモリの量が減少するのを見ることができます。最近の Windows Server には、使用可能なすべての仮想 RAM を使用してマッピングを構築する「機能」がありました。だから... FileCopy(またはFileCopyEx)を使用して、OSにデータを移動するための最良の方法を決定させます(OSが最もよく知っている可能性があります)。別のスレッドで実行する場合、プログラムを停止せずに実行することもできます。ほとんどの CPU はほとんどの時間をディスク/ネットワークを待機する爪のバフに費やすため、非常に迅速なコピーになります。

あなたの例では、CreateFileMapping を PAGE_READONLY に、MapViewOfFile を FILE_MAP_READ にすべきではありませんか? 返されたポインター (FMappingPtr) は、デバッガーで表示される有効な場所を指している必要があります。ファイルのように見えるはずです。

于 2011-03-14T18:25:42.167 に答える