当前位置:  开发笔记 > 编程语言 > 正文

如何将一个流的内容复制到另一个流?

如何解决《如何将一个流的内容复制到另一个流?》经验,为你挑选了3个好方法。

将一个流的内容复制到另一个流的最佳方法是什么?有没有标准的实用方法?



1> Nick..:

从.NET 4.5开始,有Stream.CopyToAsync方法

input.CopyToAsync(output);

这将返回一个Task可以在完成时继续,如下所示:

await input.CopyToAsync(output)

// Code from here on will be run in a continuation.

请注意,根据调用的位置,后面CopyToAsync的代码可能会也可能不会在调用它的同一个线程上继续.

SynchronizationContext调用时被抓获await将决定线程的延续将被执行的.

此外,此调用(这是一个可能会更改的实现细节)仍然会对读取和写入进行序列化(它不会浪费线程阻塞I/O完成).

从.NET 4.0开始,就是Stream.CopyTo方法

input.CopyTo(output);

对于.NET 3.5及之前的版本

框架中没有任何东西可以帮助解决这个问题; 你必须手动复制内容,如下所示:

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[32768];
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write (buffer, 0, read);
    }
}

注1:此方法允许您报告进度(到目前为止读取的x个字节...)
注2:为什么使用固定的缓冲区大小而不是input.Length?因为该长度可能无法使用!来自文档:

如果从Stream派生的类不支持搜索,则调用Length,SetLength,Position和Seek会抛出NotSupportedException.


请注意,这不是最快的方法.在提供的代码段中,您必须等待Write完成才能读取新块.异步读取和写入时,等待将消失.在某些情况下,这将使复制速度提高两倍.但是它会使代码变得更加复杂,所以如果速度不是问题,请保持简单并使用这个简单的循环.StackOverflow上的这个问题有一些代码说明异步读/写:http://stackoverflow.com/questions/1540658/net-asynchronous-stream-read-write问候,Sebastiaan
FWIW,在我的测试中,我发现4096实际上比32K更快.与CLR如何在特定大小上分配块有关.因此,Stream.CopyTo的.NET实现显然使用了4096.

2> Joshua..:

MemoryStream有.WriteTo(outstream);

和.NET 4.0在普通流对象上有.CopyTo.

.NET 4.0:

instream.CopyTo(outstream);


复制后需要重新传递流:instream.Position = 0;
除了重写输入流之外,我还发现需要回滚输出流:outstream.Position = 0;
这是因为它们是.NET 4.0中的新功能.Stream.CopyTo()基本上对批准的答案所做的循环完全相同,并进行一些额外的健全性检查.默认缓冲区大小为4096,但指定较大的缓冲区也存在重载.

3> Eloff..:

我使用以下扩展方法.当一个流是MemoryStream时,它们已经优化了重载.

    public static void CopyTo(this Stream src, Stream dest)
    {
        int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
        byte[] buffer = new byte[size];
        int n;
        do
        {
            n = src.Read(buffer, 0, buffer.Length);
            dest.Write(buffer, 0, n);
        } while (n != 0);           
    }

    public static void CopyTo(this MemoryStream src, Stream dest)
    {
        dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
    }

    public static void CopyTo(this Stream src, MemoryStream dest)
    {
        if (src.CanSeek)
        {
            int pos = (int)dest.Position;
            int length = (int)(src.Length - src.Position) + pos;
            dest.SetLength(length); 

            while(pos < length)                
                pos += src.Read(dest.GetBuffer(), pos, length - pos);
        }
        else
            src.CopyTo((Stream)dest);
    }

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有