Stream.CopyTo(Stream) 会损坏数据吗?

Posted

技术标签:

【中文标题】Stream.CopyTo(Stream) 会损坏数据吗?【英文标题】:Can Stream.CopyTo(Stream) Corrupt Data? 【发布时间】:2012-08-01 18:05:26 【问题描述】:

背景:

我有以下 WriteFileToStream 函数,旨在完成一项简单的工作:从文件中获取数据并将其复制到 Stream。

我最初使用的是 Stream.CopyTo(Stream) 方法。然而,经过漫长的调试过程,我发现这是在我的处理管道中进一步出现“损坏数据”错误的原因。

简介:

使用 Stream.CopyTo(Stream) 方法会产生 65536 字节的数据,并且流无法正确处理。

使用 Stream.Write(...) 方法产生 45450 字节的数据并且流处理正确。

问题:

任何人都知道为什么 CopyTo 的以下用法可能会导致将无关数据写入流中吗?

请注意:WriteFileToStream 中的最终代码取自对该问题的回答:Save and load MemoryStream to/from a file

public static void WriteFileToStream(string fileName, Stream outputStream)

    FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
    long fileLength = file.Length;
    byte[] bytes = new byte[fileLength];
    file.Read(bytes, 0, (int)fileLength);
    outputStream.Write(bytes, 0, (int)fileLength);
    file.Close();
    outputStream.Close();

    // This was corrupting the data - adding superflous bytes to the result...somehow.
    //using (FileStream file = File.OpenRead(fileName))
    //
    //    // 
    //    file.CopyTo(outputStream);
    //

【问题讨论】:

通过查看您正在混合的代码 - 您的 代码有错误,可能会将多余的数据写入目的地,而 CopyTo() 实际上工作正常。 忠告:作为开发人员,这始终是我们的错。它(几乎)从来不是操作系统或框架中的错误。 使用 MSDN 示例时,您的控制台输出是什么样的:msdn.microsoft.com/en-us/library/dd782932.aspx 【参考方案1】:

看看这段代码:

byte[] bytes = new byte[fileLength];
file.Read(bytes, 0, (int)fileLength);

一开始就坏了。您忽略了Stream.Read 的结果。 永远不要那样做。假设文件在获取长度和从中读取之间被截断 - 你会写一堆零。假设无论出于何种原因,Read 调用不会读取整个数据,即使它在那里(不太可能是本地文件,但如果通过网络访问的文件可能表现出这种行为,我不会感到惊讶) - 再次,你会错误地写一堆零。

话虽如此,这肯定是一个奇怪的情况。就个人而言,我总是尝试将流 视为流 - 我不喜欢根据该值获取大小和预分配。例如,如果文件在您阅读时增长,您的代码可以很好地证明该问题。在不知道更多细节的情况下,我不知道这是否可能。

但不,就我所知,Stream.CopyTo 很好。我认为问题更可能出在其他地方。

请注意,在您注释掉的版本中,您不会关闭输出流 - 而在显式读取文件的版本中(不使用 using 语句,顺便说一句...)您会这样做。

您能否可靠地重现该问题?一个简短但完整的程序来演示这个问题将更有可能说服我框架中的一个错误:)

【讨论】:

乔恩:为什么我需要在存在using 语句的情况下关闭流? @JTech:不清楚您指的是我的回答中的哪一点。但如果 Read 调用引发异常,您当前的代码将保持开放流。【参考方案2】:

我已经评论了我认为你的错误在哪里。

public static void WriteFileToStream(string fileName, Stream outputStream)

    FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
    long fileLength = file.Length; //bug
    byte[] bytes = new byte[fileLength];
    file.Read(bytes, 0, (int)fileLength);
    outputStream.Write(bytes, 0, (int)fileLength); //bug
    file.Close();
    outputStream.Close();

    //your code here should work when you fix the bug

这就是你想要的:

long fileLength = outputStream.Length;

outputStream.Write(bytes, 0, bytes.Length);

【讨论】:

长文件长度 = outputStream.Length; // 这导致 'fileLength' 为 0 - 这本身就是一个错误。

以上是关于Stream.CopyTo(Stream) 会损坏数据吗?的主要内容,如果未能解决你的问题,请参考以下文章

Windows /.NET 的 System.Drawing.Save(Stream, ImageFormat) 中的错误。损坏的 PNG 生成

从 Qt 中杀死 ffmpeg 会导致视频文件损坏

从在线流中记录的损坏的 AAC 文件

重温网络编程——协议

为啥具有短路操作的并行 Java Stream 会评估 Stream 的所有元素,而顺序 Stream 不会?

UDP 数据是不是会损坏?