Delphi:将FileStream复制到MemoryStream

时间:2010-06-05 00:03:13

标签: delphi delphi-7

我想将FileStream的一部分复制到MemoryStream。

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

是吗?它不适合我。

2 个答案:

答案 0 :(得分:19)

你必须从FileStream中读取()到一个单独的缓冲区,然后将Write()传递给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);

答案 1 :(得分:0)

以下解决方案不使用单独的缓冲区作为已发布的解决方案。而是直接写入目标内存流的缓冲区。 这更快,因为另一个解决方案复制两次,首先复制到临时缓冲区,最后复制到内存流中。

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

这是有效的,因为SetSize还分配了内存流的缓冲区。 请参阅SetSize documentation

  

使用 SetSize 在填充数据之前设置内存流的大小。 SetSize 分配内存缓冲区以保存NewSize字节[...]。

我还使用CopyFrom测试了该解决方案,但该解决方案使用巨型文件非常慢,因为它似乎使用非常小的缓冲区。

如果要使用上面的方法直接读取文件,可以使用自己的函数来完成,该函数直接将块读取到内存流中。为了比CopyFrom方法更快,这些块应该更大。以下代码使用灵活的缓冲区,例如256 MiB。请随意使用它。

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.