Подтвердить что ты не робот

Delphi: копирование FileStream в MemoryStream

Я хочу скопировать часть FileStream в MemoryStream.

FileStream.Write(Pointer(MemoryStream)^, MemoryStream.Size);
FileStream.Read(Pointer(MemoryStream)^, count);

Это правильно? Это не работает для меня.

4b9b3361

Ответ 1

Вы должны прочитать() из FileStream в отдельный буфер, а затем записать() в MemoryStream, то есть:

var
  Buffer: PByte;

GetMem(Buffer, NumberOfBytes);
try
  FileStream.ReadBuffer(Buffer^, NumberOfBytes);
  MemoryStream.WriteBuffer(Buffer^, NumberOfBytes);
finally
  FreeMem(Buffer);
end;

Поскольку вы имеете дело с двумя объектами TStream, было бы проще использовать метод TStream.CopyFrom(), а именно:

MemoryStream.CopyFrom(FileStream, NumberOfBytes);

Ответ 2

Следующее решение не использует отдельный буфер в качестве решения, которое уже было опубликовано. Вместо этого он записывает непосредственно в буфер целевого потока памяти. Это быстрее, потому что другое решение копирует дважды, сначала во временный буфер и, наконец, в поток памяти.

...
try
  MemoryStream.SetSize(NumberOfBytes); // Allocating buffer
  FileStream.ReadBuffer(MemoryStream.Memory^, NumberOfBytes);
finally
  MemoryStream.Free();
...

Это работает, потому что SetSize также выделяет буфер потока памяти. См. Документацию SetSize.

Используйте SetSize, чтобы установить размер потока памяти перед заполнением его данными. SetSize выделяет буфер памяти для хранения байтов NewSize [...].


Я также протестировал решение с CopyFrom, но это решение очень медленно работает с гигантскими файлами, потому что кажется, что он использует очень маленький буфер.

Если файлы очень удобны для чтения напрямую описанным выше способом, это можно сделать с помощью собственной функции, которая считывает фрагменты непосредственно в поток памяти. Чтобы быть быстрее метода CopyFrom, эти куски должны быть больше. Следующий код использует гибкий буфер, например, 256 МБ. Пожалуйста, не стесняйтесь сделать функцию из этого.

var
  ...
  MemoryStreamPointer: Pointer;
  BlockSize: Integer;
  BytesToRead: Integer;
  BytesRead: Integer;
  RemainingBytes: Integer;

begin
  ...
  BlockSize := 256 * 1024 * 1024; // 256 MiB block size

  MemoryStream.SetSize(NumberOfBytes); // Allocating buffer
  MemoryStreamPointer := MemoryStream.Memory;

  RemainingBytes := NumberOfBytes;
  while RemainingBytes > 0 do
  begin
    BytesToRead := min(RemainingBytes, BlockSize);
    BytesRead := FileStream.Read(MemoryStreamPointer^, BytesToRead);
    RemainingBytes := RemainingBytes - BytesRead;
    MemoryStreamPointer := Pointer(NativeInt(MemoryStreamPointer) + BytesRead);
  end;
  ...
end;

Пожалуйста, обратите внимание, что приведенный выше код не содержит обработки ошибок. Далее подумайте об установке позиции потоков файлов в 0 перед чтением.