File Mapping, чтобы копировать быстрее? - PullRequest
2 голосов
/ 14 марта 2011

Я подал заявку на копирование файла, используя поток и метод 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;

Где моя проблема?

Ответы [ 2 ]

2 голосов
/ 14 марта 2011

Не то чтобы я не соглашался с комментариями к вашему вопросу, но есть две причины, по которым ваш код не сработал.

Во-первых, вы указываете 2Kb для dwFileOffsetLow с CreateFileMapping, но затем передаете весь размер файла в WriteFile. С этим отображением представления, WriteFile должен вызываться не более 2Kb для 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'.

2 голосов
/ 14 марта 2011

Система FileCopy использует файлы, отображенные в памяти. Если файл большой, вы можете наблюдать за уменьшением объема виртуальной памяти в вашей системе, когда происходит сопоставление. Недавно в Windows Server появилась «функция», которая использовала бы всю доступную виртуальную память для построения сопоставления. Итак ... Я бы использовал FileCopy (или FileCopyEx) и позволил ОС выбрать лучший способ перемещения данных (вероятно, он знает лучше). Если вы делаете это в отдельном потоке, вы можете даже сделать это, не останавливая свою программу - и это будет очень быстрая копия, поскольку большинство процессоров будут тратить большую часть времени, копируя свои гвозди в ожидании диска / сети.

В вашем примере не должны ли вы быть CreateFileMapping с PAGE_READONLY и MapViewOfFile с FILE_MAP_READ? Возвращенный указатель (FMappingPtr) должен указывать на действительный, видимый в отладчике - и он должен выглядеть как ваш файл.

...