目前我有这段代码
SessionStream(Request.Content.ReadAsStreamAsync(), new { });
我需要某种方式"镜像"传入流,以便我有两个实例。 像下面的伪代码:
Task<Stream> stream = Request.Content.ReadAsStreamAsync();
SessionStream(stream, new { });
Stream theotherStram;
stream.Result.CopyToAsync(theotherStram)
ThoOtherStream(theotherStram, new { });
答案 0 :(得分:2)
一种始终有效的技术是将流复制到MemoryStream
,然后使用它。
通常,使用Seek
方法查找原始流更有效率。只有在此流支持搜索时才有效。
如果你不想缓冲并且不能寻求你需要按两个消费者的方式按顺序推送流内容。读一个块,写两次。
如果另外你需要一个拉模型(即手工可读流到某个组件),它会变得非常困难并涉及线程。你需要编写一个总是很难的推拉式适配器。
答案 1 :(得分:0)
usr 的答案在 2020 年仍然是正确的,但对于那些想知道为什么它不是微不足道的人来说,这里有一个简短的解释。
流背后的想法是写入流和读取流是独立的。通常,读取过程比写入快得多(考虑通过网络接收数据 - 您可以在数据到达时立即读取数据),因此读取器通常会等待数据的新部分,一到达就进行处理,然后删除它以释放内存,然后等待下一部分。
这允许在不使用太多 RAM 的情况下处理潜在的无限数据流(例如,应用程序日志流)。
假设现在我们有 2 个读者(根据问题的要求)。数据部分到达,然后我们必须等待两个读取器都读取数据,然后才能删除它。这意味着它必须存储在内存中,直到两个读者都完成了它。问题是读者可以以非常不同的速度处理数据。例如。一个可以将其写入文件,另一个可以计算内存中的符号。在这种情况下,要么快的必须等待慢的才能进一步读取,要么我们需要将数据保存到内存中的缓冲区,让读者从中读取。在最坏的情况下,我们最终会在内存中得到输入流的完整副本,基本上是创建了一个内存流实例。
要实现第一个选项,您必须实现一个流读取器,它知道哪个流使用速度更快,并考虑到这一点,会相应地分发和丢弃数据。
如果你确定你有足够的内存,并且处理速度不是很关键,那么就使用内存流:
using var memStream = new MemoryStream();
await incomingStream.CopyToAsync(memStream);
UseTheStreamForTheFirstTime(memStream);
memStream.Seek(0, SeekOrigin.Begin);
UseTheStreamAnotherTime(memStream);