MemoryStream.WriteTo(Stream destinationStream)与Stream.CopyTo(Stream destinationStream)

时间:2012-05-19 10:42:06

标签: c# .net stream memorystream

哪一个更好:MemoryStream.WriteTo(Stream destinationStream)Stream.CopyTo(Stream destinationStream) ??

我正在讨论没有Buffer的这两种方法的比较,因为我这样做:

Stream str = File.Open("SomeFile.file");
MemoryStream mstr = new MemoryStream(File.ReadAllBytes("SomeFile.file"));

using(var Ms = File.Create("NewFile.file", 8 * 1024))
{
    str.CopyTo(Ms) or mstr.WriteTo(Ms);// Which one will be better??
}

更新

这是我想做的事:

  • 打开文件[说“X”类型文件]
  • 解析内容
  • 从这里我得到了一堆新的流[3~4个文件]
  • Parse One Stream
  • 提取数千个文件[Stream是图像文件]
  • 将其他流保存到文件
  • 编辑所有文件
  • 生成新的“X”类型文件。

我写了一些实际工作正常的代码。

但是现在我正在优化代码以提高效率。

6 个答案:

答案 0 :(得分:16)

历史事故有两种方法可以做同样的事情。 MemoryStream总是有WriteTo()方法,Stream直到.NET 4才获得CopyTo()方法。

MemoryStream.WriteTo()版本如下所示:

public virtual void WriteTo(Stream stream)
{
    // Exception throwing code elided...
    stream.Write(this._buffer, this._origin, this._length - this._origin);
}

Stream.CopyTo()实现如下:

private void InternalCopyTo(Stream destination, int bufferSize)
{
    int num;
    byte[] buffer = new byte[bufferSize];
    while ((num = this.Read(buffer, 0, buffer.Length)) != 0)
    {
        destination.Write(buffer, 0, num);
    }
}

Stream.CopyTo()更通用,适用于任何流。并帮助程序员摸索从NetworkStream复制数据。忘记关注Read()的返回值是一个非常的常见错误。但它当然会复制字节两次并分配临时buffer,MemoryStream不需要它,因为它可以直接从自己的缓冲区写入。所以你仍然喜欢WriteTo()。注意到差异的可能性不大。

答案 1 :(得分:6)

MemoryStream.WriteTo:将此内存流的全部内容写入另一个流。

Stream.CopyTo:从当前流中读取字节并将其写入目标流。复制从当前流中的当前位置开始。 您需要回到0,才能复制整个源流。

所以我认为MemoryStream.WriteTo是这种情况的更好选择

答案 2 :(得分:4)

如果使用Stream.CopyTo,则无需将所有字节读入内存即可。但是:

  • 如果您刚使用File.Copy
  • ,此代码会更简单
  • 如果 要将所有数据加载到内存中,您只需使用:

    byte[] data = File.ReadAllBytes("input");
    File.WriteAllBytes("output", data);
    
  • 您应该输入using语句以及输出流

如果您真的需要处理,那么无法使用File.Copy,使用Stream.CopyTo将处理更大的文件,而不是将所有内容加载到内存中。当然,您可能不需要它,或者由于其他原因,您可能需要将整个文件加载到内存中。

如果 得到MemoryStream,我可能会使用MemoryStream.WriteTo而不是Stream.CopyTo,但它可能对您没有多大影响使用,除了,您需要确保在使用CopyTo时确保您在流的开头。

答案 3 :(得分:1)

我认为Hans Passant声称MemoryStream.WriteTo()中的错误是错误的;它不会“忽略Write()的返回值”。 Stream.Write()返回void,这意味着我写入了整个计数字节,这意味着Stream.Write()将根据需要阻塞完成对NetworkStream的操作,如果最终失败则抛出。

这确实不同于?nix中的write()系统调用,以及libc中的许多仿真等等,可以返回“短写”。我怀疑汉斯跳出了Stream.Write()的结论,我也没想到,但显然它没有。

可以想象Stream.Write()可以执行“短写”,而不返回任何指示,要求调用者检查Stream的Position属性是否实际上已按计数提前。这将是一个非常容易出错的API,我怀疑它是这样做的,但我没有彻底测试它。 (测试它会有点棘手:我认为你需要连接一个TCP NetworkStream与另一端的读取器永远阻塞,并写入足以填充线缓冲区。或类似的东西......)< / p>

Stream.Write()的注释不是很明确:

要点:   在派生类中重写时,将一个字节序列写入当前字节 按数字流式传输并提升此流中的当前位置 写的字节数。   参数:buffer: 一个字节数组。此方法将计数字节从缓冲区复制到当前流。

将其与写入(2)的Linux手册页进行比较:

write()写入从缓冲区指向的buf计数字节到文件描述符fd引用的文件。

注意关键的“最多”。这句话之后是对可能发生“短写”的一些条件的解释,使其明确表明它可能发生。

这确实是一个关键问题:我们需要知道Stream.Write()的行为,毫无疑问。

答案 4 :(得分:0)

CopyTo方法创建一个缓冲区,用原始流中的数据填充它,然后调用Write方法将创建的缓冲区作为参数传递。 WriteTo使用memoryStream的内部缓冲区进行写入。这就是区别。什么是更好的 - 由你决定你喜欢哪种方法。

答案 5 :(得分:0)

从Vb.Net中的HttpInputStream创建MemoryStream:

Dim filename As String = MyFile.PostedFile.FileName
Dim fileData As Byte() = Nothing
Using binaryReader = New BinaryReader(MyFile.PostedFile.InputStream)
    binaryReader.BaseStream.Position = 0
    fileData = binaryReader.ReadBytes(MyFile.PostedFile.ContentLength)
End Using
Dim memoryStream As MemoryStream = New MemoryStream(fileData)