Can Stream.CopyTo(Stream)损坏的数据

本文关键字:Stream 数据 损坏 CopyTo Can | 更新日期: 2024-09-19 20:55:21

背景:

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

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

剧情简介:

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

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

问题:

有人能理解为什么以下CopyTo的使用可能会导致将无关数据写入流吗?

请注意:WriteFileToStream中的最后一段代码取自这个问题的答案:将MemoryStream保存到文件并从文件加载MemoryStream

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);
    //}
}

Can Stream.CopyTo(Stream)损坏的数据

看看这个代码:

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

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

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

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

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

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

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

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