Delphi: копирование FileStream в MemoryStream - PullRequest
14 голосов
/ 05 июня 2010

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

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

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

Ответы [ 2 ]

19 голосов
/ 05 июня 2010

Вы должны прочитать () из 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);
0 голосов
/ 25 марта 2018

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

...
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 перед чтением.

...