从一个流复制到另一个流?

8

我的项目要求使用 .Net 2.0,因此我不能使用后来推出的方便的 CopyTo 函数。

我需要将来自 HttpWebResponse 的响应流复制到另一个流(很可能是 MemoryStream,但可以是任何 Stream 子类)。 我通常的策略是:

BufferedStream bufferedresponse = new BufferedStream(HttpResponse.GetResponseStream());
int count = 0;
byte[] buffer = new byte[1024];
do {
    count = bufferedresponse.Read(buffer, 0, buffer.Length);
    target.Write(buffer, 0, count);
} while (count > 0);
bufferedresponse.Close();

有更有效的方法吗?缓冲区大小真的很重要吗?在.Net 2.0中从一个流复制到另一个流的最佳方法是什么?

P.S. 这是为了下载大型的200+ MB GIS tif图像。当然,可靠性是最重要的。


3
可能是在两个Stream实例之间复制的最佳方法的重复问题。同时所选择的答案就是您目前正在做的,因此我认为您正在正确地进行操作。 - Chris Walsh
在我的问题被关闭之前,我想说一下我的问题涉及到 .Net 2.0 的限制。希望这足以使它保持开放状态,我不想让我的问题被关闭 :( - Corey Ogburn
我链接的问题有一个使用你的方法以及更新的CopyTo方法的答案。值得一提的是,如果适用于您的用例,您将获得更好的性能,即等待整个流进来,然后将流复制到较大的块中。但这并不总是理想的。 - Chris Walsh
4个回答

9

这是一个方便的函数。是的,缓冲区大小很重要。增加它可能会在处理大文件时提供更好的性能。

public static void WriteTo(Stream sourceStream, Stream targetStream)
{
       byte[] buffer = new byte[0x10000];
       int n;
       while ((n = sourceStream.Read(buffer, 0, buffer.Length)) != 0)
           targetStream.Write(buffer, 0, n);
}

3
缓冲区的大小很重要。例如,如果你一次复制1兆字节的数据,按字节计算,就需要遍历2^20个循环。如果一次复制1千字节,你只需遍历2^10个循环。当你调用了上百万次Read和Write时,会带来显著的开销。
对于读取FileStream,我通常使用64K到256K之间的缓冲区。小于32K的缓冲区性能显著下降,大于256K也是如此。使用64K缓冲区和256K缓冲区之间的差别不值得额外的内存消耗。请注意,这些数字是基于我的系统和网络,你的数字会根据硬件和操作系统而变化。
对于网络流,请选择一个能跟上传入数据流的缓冲区大小。建议至少4千字节,这样可以在写入因任何原因停顿时给你一些缓冲区。

1

你可以摆脱 BufferedStream,它只有在读取流的小块时才有用。只需将响应流存储在一个变量中并使用即可:

Stream response = HttpResponse.GetResponseStream();

缓冲区太小会降低性能。您可以使用更大的缓冲区,以便至少可以容纳整个IP数据包的数据。我稍微查了一下,4096字节应该足够了。实际上,您可以使用任何大小的缓冲区,最多可达85 kb,在此之后,它将分配在大对象堆中,如果没有理由,您应该避免这样做。

除此之外,它的效率已经达到了极致。


0

我能想到两种方法。

  1. 检查Stream.MemberWiseClone()是否符合您的需求。它可以为您获取对象的浅层副本。

  2. 如果两端都是Stream类型,请检查此方法是否有效。

    BufferedStream bs = new BufferedStream((Stream)memoryStreamObject);


这些方法只是提供了另一种访问相同流的方式,为此您可以将流引用复制到另一个变量中... - Guffa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接