我想将FileStream的一部分复制到MemoryStream。
FileStream.Write(Pointer(MemoryStream)^, MemoryStream.Size);
FileStream.Read(Pointer(MemoryStream)^, count);
是吗?它不适合我。
答案 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.