如何将一个流的内容复制到另一个流?
将一个流的内容复制到另一个流的最佳方法是什么?是否有一个标准的实用方法?
What is the best way to copy the contents of one stream to another? Is there a standard utility method for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
从 .NET 4.5 开始,出现了 < code>Stream.CopyToAsync 方法
这将返回一个
Task
完成后可以继续,如下所示:请注意,这取决于对
CopyToAsync
的调用位置,后面的代码可能会也可能不会在调用它的同一线程上继续。SynchronizationContext
是调用await
时捕获将确定延续将在哪个线程上执行。此外,此调用(这是一个可能会更改的实现细节)仍然对读取和写入进行排序(它只是不会浪费 I/O 完成时阻塞的线程)。
从 .NET 4.0 开始,出现了 < code>Stream.CopyTo 方法
对于 .NET 3.5 及之前版本
框架中没有任何内容可以帮助实现此目的;您必须手动复制内容,如下所示:
注意 1:此方法将允许您报告进度(到目前为止已读取 x 字节...)
注 2:为什么使用固定缓冲区大小而不是
input.Length
?因为该长度可能不可用!来自文档:From .NET 4.5 on, there is the
Stream.CopyToAsync
methodThis will return a
Task
that can be continued on when completed, like so:Note that depending on where the call to
CopyToAsync
is made, the code that follows may or may not continue on the same thread that called it.The
SynchronizationContext
that was captured when callingawait
will determine what thread the continuation will be executed on.Additionally, this call (and this is an implementation detail subject to change) still sequences reads and writes (it just doesn't waste a threads blocking on I/O completion).
From .NET 4.0 on, there's is the
Stream.CopyTo
methodFor .NET 3.5 and before
There isn't anything baked into the framework to assist with this; you have to copy the content manually, like so:
Note 1: This method will allow you to report on progress (x bytes read so far ...)
Note 2: Why use a fixed buffer size and not
input.Length
? Because that Length may not be available! From the docs:MemoryStream
在普通流对象上有
.WriteTo(outstream);
,.NET 4.0 有.CopyTo
。.NET 4.0:
MemoryStream
has.WriteTo(outstream);
and .NET 4.0 has
.CopyTo
on normal stream object..NET 4.0:
我使用以下扩展方法。当一个流是 MemoryStream 时,他们优化了重载。
I use the following extension methods. They have optimized overloads for when one stream is a MemoryStream.
.NET Framework 4 引入了 System.IO 命名空间的 Stream 类的新“CopyTo”方法。使用此方法,我们可以将一个流复制到不同流类的另一个流。
这是一个例子。
.NET Framework 4 introduce new "CopyTo" method of Stream Class of System.IO namespace. Using this method we can copy one stream to another stream of different stream class.
Here is example for this.
实际上,有一种不那么严厉的方法来进行流复制。但请注意,这意味着您可以将整个文件存储在内存中。如果您正在处理数百兆字节或更多的文件,请不要在不小心的情况下尝试使用此功能。
注意:还可能存在一些有关二进制数据和字符编码的问题。
There is actually, a less heavy-handed way of doing a stream copy. Take note however, that this implies that you can store the entire file in memory. Don't try and use this if you are working with files that go into the hundreds of megabytes or more, without caution.
NOTE: There may also be some issues concerning binary data and character encodings.
区分“CopyStream”实现的基本问题是:
这些问题的答案会导致 CopyStream 的实现截然不同,并且取决于您拥有的流类型以及您想要优化的内容。 “最佳”实现甚至需要知道流正在读取和写入哪些特定硬件。
The basic questions that differentiate implementations of "CopyStream" are:
The answers to these questions result in vastly different implementations of CopyStream and are dependent on what kind of streams you have and what you are trying to optimize. The "best" implementation would even need to know what specific hardware the streams were reading and writing to.
不幸的是,没有真正简单的解决方案。您可以尝试类似的操作:
但是如果没有任何内容可读取,Stream 类的不同实现可能会表现不同。从本地硬盘驱动器读取文件的流可能会阻塞,直到读取操作从磁盘读取了足够的数据来填充缓冲区,并且只有在到达文件末尾时才返回较少的数据。另一方面,即使还有更多数据需要接收,从网络读取的流也可能返回更少的数据。
在使用通用解决方案之前,请务必检查您正在使用的特定流类的文档。
Unfortunately, there is no really simple solution. You can try something like that:
But the problem with that that different implementation of the Stream class might behave differently if there is nothing to read. A stream reading a file from a local harddrive will probably block until the read operaition has read enough data from the disk to fill the buffer and only return less data if it reaches the end of file. On the other hand, a stream reading from the network might return less data even though there are more data left to be received.
Always check the documentation of the specific stream class you are using before using a generic solution.
可能有一种方法可以更有效地完成此操作,具体取决于您使用的流类型。如果您可以将一个或两个流转换为 MemoryStream,则可以使用 GetBuffer 方法直接使用表示数据的字节数组。这使您可以使用 Array.CopyTo 之类的方法,该方法可以抽象出 Friedguybob 引发的所有问题。您可以相信 .NET 知道复制数据的最佳方式。
There may be a way to do this more efficiently, depending on what kind of stream you're working with. If you can convert one or both of your streams to a MemoryStream, you can use the GetBuffer method to work directly with a byte array representing your data. This lets you use methods like Array.CopyTo, which abstract away all the issues raised by fryguybob. You can just trust .NET to know the optimal way to copy the data.
如果您想要一个程序将流复制到其他程序,那么尼克发布的程序就可以,但它缺少位置重置,应该是,
但是如果它在运行时不使用程序,您应该使用内存流
if you want a procdure to copy a stream to other the one that nick posted is fine but it is missing the position reset, it should be
but if it is in runtime not using a procedure you shpuld use memory stream
由于没有一个答案涵盖从一个流复制到另一个流的异步方式,因此我在端口转发应用程序中成功使用了一种模式,将数据从一个网络流复制到另一个网络流。它缺乏强调模式的异常处理。
Since none of the answers have covered an asynchronous way of copying from one stream to another, here is a pattern that I've successfully used in a port forwarding application to copy data from one network stream to another. It lacks exception handling to emphasize the pattern.
对于 .NET 3.5 及之前尝试:
For .NET 3.5 and before try :
简单又安全 - 从原始来源创建新流:
Easy and safe - make new stream from original source:
将 Stream 复制到 MemoryStream 的问题
以下代码解决了使用 CopyTo //任何需要输入流的函数 。在我的例子中,将 PDF 文件保存为流
文档.保存(流);
//注意 - 请将流放置在finally块中,而不是放置在using块中,因为它会抛出错误“流关闭时访问被拒绝”
The following code to solve the issue copy the Stream to MemoryStream using CopyTo
//any function require input the stream. In mycase to save the PDF file as stream
document.Save(stream);
//Note - please dispose the stream in the finally block instead of inside using block as it will throw an error 'Access denied as the stream is closed'