Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在.NET中拆分(复制)流?_C#_.net_Io_Stream - Fatal编程技术网

C# 如何在.NET中拆分(复制)流?

C# 如何在.NET中拆分(复制)流?,c#,.net,io,stream,C#,.net,Io,Stream,有人知道在哪里可以找到流拆分器实现吗 我希望获得一个流,并获得两个独立的流,它们可以独立读取和关闭,而不会相互影响。这些流应该返回与原始流相同的二进制数据。无需执行定位或搜索等。。。只向前 我更希望它不只是将整个流复制到内存中并多次提供,这将非常简单,可以自己实现 有什么东西可以做到这一点吗?不是现成的 您需要以FIFO方式缓冲原始流中的数据,仅丢弃所有“读取器”流读取的数据 我会使用: 一个“管理”对象,持有某种字节[]队列,持有要缓冲的区块,并在需要时从源流读取额外数据 一些“读取器”实例

有人知道在哪里可以找到流拆分器实现吗

我希望获得一个流,并获得两个独立的流,它们可以独立读取和关闭,而不会相互影响。这些流应该返回与原始流相同的二进制数据。无需执行定位或搜索等。。。只向前

我更希望它不只是将整个流复制到内存中并多次提供,这将非常简单,可以自己实现

有什么东西可以做到这一点吗?

不是现成的

您需要以FIFO方式缓冲原始流中的数据,仅丢弃所有“读取器”流读取的数据

我会使用:

  • 一个“管理”对象,持有某种字节[]队列,持有要缓冲的区块,并在需要时从源流读取额外数据
  • 一些“读取器”实例知道它们正在读取的缓冲区的位置和位置,它们从“管理”请求下一个块,并在不再使用块时通知它,以便将其从队列中删除

    • 我认为您无法找到一个通用的实现来实现这一点。流相当抽象,您不知道字节来自何处。例如,你不知道它是否支持寻找;你不知道运营的相对成本。(流可能是从远程服务器读取数据的抽象,甚至是从备份磁带读取数据的抽象!)

      如果您能够拥有一个MemoryStream并存储一次内容,那么您可以使用相同的缓冲区创建两个单独的流;它们将作为独立的流运行,但只使用内存一次


      否则,我认为最好创建一个包装类来存储从一个流读取的字节,直到它们也被第二个流读取。这将为您提供所需的仅向前的行为-但在最坏的情况下,您可能会冒险将所有字节存储在内存中,如果第二个流在第一个流读取完所有内容后才被读取。

      如果不复制至少一部分源流,您就无法真正做到这一点,这主要是因为如果听起来您无法控制它们的消耗速率(多线程?)。你可以做一些聪明的事情,一个读一个读另一个(从而只在那一点上复制),但这听起来很复杂,不值得麻烦

      如果流分别处于BOF和EOF,则在不冒将所有内容都保留在内存中的风险的情况下,这可能会很棘手


      我想知道是否将流写入磁盘、复制它、让两个流从磁盘读取、并在
      Close()
      中内置自删除功能(即,围绕
      FileStream
      编写您自己的
      stream
      包装器)会更容易些。

      下面的内容似乎被称为EchoStream 这是一个非常古老的实现(2003年),但应该提供一些上下文


      通过

      发现,引入async/await后,只要您的所有读取任务(除一个外)都是异步的,您就应该能够使用一个操作系统线程处理相同的数据两次

      我认为您需要的是一个到目前为止您已经看到的数据块的链接列表。然后,您可以有多个自定义流实例,其中包含指向此列表的指针。当块从列表的末尾脱落时,它们将被垃圾收集。立即重用内存需要一些其他类型的循环列表和引用计数。可行,但更复杂

      当您的自定义流可以从缓存应答ReadAsync调用时,复制数据,将指针向下移动到列表并返回

      当流到达缓存列表的末尾时,您希望在不等待的情况下向底层流发出单个ReadAsync,并使用数据块缓存返回的任务。因此,如果任何其他流读取器也赶上并尝试在读取完成之前读取更多内容,则可以返回相同的任务对象


      这样,两个读卡器都将其等待继续挂接到同一个ReadAsync调用的结果。当单一读取返回时,两个读取任务将依次执行其流程的下一步。

      我已经在github和NuGet上提供了一个SplitStream

      事情是这样的

      using (var inputSplitStream = new ReadableSplitStream(inputSourceStream))
      
      using (var inputFileStream = inputSplitStream.GetForwardReadOnlyStream())
      using (var outputFileStream = File.OpenWrite("MyFileOnAnyFilestore.bin"))
      
      using (var inputSha1Stream = inputSplitStream.GetForwardReadOnlyStream())
      using (var outputSha1Stream = SHA1.Create())
      {
          inputSplitStream.StartReadAhead();
      
          Parallel.Invoke(
              () => {
                  var bytes = outputSha1Stream.ComputeHash(inputSha1Stream);
                  var checksumSha1 = string.Join("", bytes.Select(x => x.ToString("x")));
              },
              () => {
                  inputFileStream.CopyTo(outputFileStream);
              },
          );
      }
      
      我没有在非常大的溪流上测试过它,但是试一下


      github:

      类似于UNIX中的
      tee
      ,它可能需要基于循环缓冲区。如果有时间,我将尝试编写一个快速实现。这有什么用途?更不用说,如果在多线程场景中使用它,您将阻止操作系统/平台使用其自身的内在机制来拥有同一文件的多个读卡器。如果在内存中使用,最糟糕的情况永远是您可能不得不复制整个流,因此尝试这样的操作可能需要花费大量精力来注意。。。推动多消费者模式可能会更好吗