开发者

Delphi: Copy FileStream to MemoryStream

I want to copy a part of a FileStream to a MemoryStream.

FileStream.Write(Pointer(MemoryStream)^, MemoryStream.Size);
Fi开发者_运维百科leStream.Read(Pointer(MemoryStream)^, count);

Is that right? It isn't working for me.


You have to Read() from the FileStream into a separate buffer and then Write() that to the MemoryStream, ie:

var
  Buffer: PByte;

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

Since you are dealing with two TStream objects, it would be easier to use the TStream.CopyFrom() method instead, ie:

MemoryStream.CopyFrom(FileStream, NumberOfBytes);


The following solution does not use a separate buffer as the solution that was already posted. Instead it writes directly to the buffer of the destination memory stream. This is faster because the other solution copies twice, first into the temporary buffer and finally into the memory stream.

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

This works because SetSize also allocates the buffer of the memory stream. See SetSize documentation.

Use SetSize to set the Size of a memory stream before filling it with data. SetSize allocates the memory buffer to hold NewSize bytes [...].


I also tested the solution with CopyFrom, but that solution is very slow working with giant files because it seems to use a very small buffer.

If files are to great to read directly with the method above it can be done with an own function that reads chunks directly to the memory stream. In order to be faster than the CopyFrom method, these chunks should be bigger. The following code uses a flexible buffer e.g. 256 MiB. Please feel free to make a function out of it.

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;

Please take caution that the above code contains no error handling. Further think about setting the file streams position to 0 before reading.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜