9

哪个更好: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”类型文件]
  • 解析内容
  • 从这里我得到了一堆新的 Streams [ 3 ~ 4 Files ]
  • 解析一个流
  • 提取数千个文件 [ 流是图像文件 ]
  • 将其他流保存到文件
  • 编辑所有文件
  • 生成一个新的“X”型文件。

我已经编写了实际上正常工作的每一段代码..

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

4

6 回答 6

17

有两种方法可以做同样的事情,这是一个历史偶然。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()。注意到差异的可能性不大。

于 2012-05-19T13:14:15.203 回答
6

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

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

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

于 2012-05-19T10:51:45.677 回答
4

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

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

    byte[] data = File.ReadAllBytes("input");
    File.WriteAllBytes("output", data);
    
  • 您应该有一个using输入和输出流的语句

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

如果你a MemoryStream,我可能会使用MemoryStream.WriteTo而不是Stream.CopyTo,但它可能不会对你使用有太大的影响,除了你需要确保你在使用时处于流的开头CopyTo

于 2012-05-19T10:53:58.737 回答
1

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

这确实不同于 ?nix 中的 write() 系统调用,以及它在 libc 等中的许多仿真,它们可以返回“短写”。我怀疑 Hans 得出了 Stream.Write() 遵循的结论,这也是我所预料的,但显然事实并非如此。

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

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

摘要:在派生类中重写时,将字节序列写入当前流,并将该流中的当前位置前进写入的字节数。参数: buffer:一个字节数组。此方法将 count 字节从缓冲区复制到当前流。

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

write() 将缓冲区指向的 buf 中的 count 个字节写入文件描述符 fd 所引用的文件。

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

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

于 2013-06-10T13:51:17.437 回答
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)
于 2014-01-21T12:19:22.573 回答
0

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

于 2012-05-19T11:04:13.697 回答