【问题标题】:MemoryStream.WriteTo(Stream destinationStream) versus Stream.CopyTo(Stream destinationStream)MemoryStream.WriteTo(Stream destinationStream) 与 Stream.CopyTo(Stream destinationStream)
【发布时间】:2012-05-26 17:25:44
【问题描述】:

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

我正在谈论这两种方法的比较,因为我正在这样做:

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]
  • 解析一个流
  • 提取数千个文件 [ 流是一个图像文件 ]​​i>
  • 将其他流保存到文件
  • 编辑所有文件
  • 生成新的“X”类型文件。

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

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

【问题讨论】:

    标签: c# .net stream memorystream


    【解决方案1】:

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

    【讨论】:

    • 感谢您指出错误...我会记住使用CopyTo...顺便说一句,没有BufferCopyTo 方法如何??
    • 你需要写一个完整的句子,我解析不了那个。看起来缓冲区没有完全刷新:)
    • 没有BufferCopyTo 方法有多?没事吧?? :)
    • Erm,没有 buffer 就不能使用它,代码被烘焙到 .NET 框架中。它只有 4096 字节,无需担心。我怀疑我仍然不明白你的意思。但是,是的,没关系。
    • 我的意思是如果我像这样使用str.CopyTo(Ms) [没有指定bufferSize]...[它是否定义了默认缓冲区??]
    【解决方案2】:

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

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

    所以我认为 MemoryStream.WriteTo 更适合这种情况

    【讨论】:

      【解决方案3】:

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

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

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

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

      如果你有一个MemoryStream,我可能会使用MemoryStream.WriteTo而不是Stream.CopyTo,但你使用哪个可能不会有太大区别,除了 您需要确保在使用CopyTo 时位于流的开头。

      【讨论】:

      • 有 Stream.CopyTo MemoryStream 的特例吗?如果没有,MemoryStream.WriteTo 会更快,因为它不缓冲。
      • 其实并不是每次我读取文件的内容并写入...所以File.Copy不是为了这个...我有时会从byte[]初始化MemoryStream,这可能是非常大(大约 90~100 MB)..那么我应该使用MemoryStream.WriteTo 来获得更好的结果吗??
      • @I.am.WritZ:抱歉,目前还不清楚你到底想做什么。如果您可以编辑您的问题以提供确切情况,那么提供具体建议会容易得多。
      • @Jon Skeet 编辑了我的问题!
      • @I.am.WritZ:尚不清楚这是 一个 用例还是多个……或者您是否将写入文件作为中间步骤。老实说,如果您只是希望在CopyToWriteTo 之间进行选择,我怀疑它会产生很大的不同 - 您应该能够自己测试差异。思考是否有更有效的完全替代方法会更有趣。
      【解决方案4】:

      我认为 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() 的 cmets 不是很明确:

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

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

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

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          在 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)
          

          【讨论】:

            猜你喜欢
            • 2012-08-01
            • 2012-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-21
            • 2019-07-23
            相关资源
            最近更新 更多