Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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

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# 复制流的最后16个字节以外的所有字节?流末的早期检测?_C#_.net_Stream_Networkstream - Fatal编程技术网

C# 复制流的最后16个字节以外的所有字节?流末的早期检测?

C# 复制流的最后16个字节以外的所有字节?流末的早期检测?,c#,.net,stream,networkstream,C#,.net,Stream,Networkstream,这与C#有关。在这种情况下,我们需要将整个源流复制到目标流中,除了最后16个字节。 编辑:流的范围可达40GB,因此无法执行某些静态字节[]分配(例如:.ToArray()) 看一下,似乎只有当返回值为0时,我们才能可靠地确定流的结尾。返回介于0和请求大小之间的值可能意味着字节“当前不可用”(这到底意味着什么?) 目前它复制每个字节,如下所示inStream和outStream是通用的-可以是内存、磁盘或网络流(实际上还有一些) 什么是可靠的方法来确保复制除最后16个以外的所有文件?我可以考虑在

这与C#有关。在这种情况下,我们需要将整个源流复制到目标流中,除了最后16个字节。

编辑:流的范围可达40GB,因此无法执行某些静态字节[]分配(例如:.ToArray())

看一下,似乎只有当返回值为0时,我们才能可靠地确定流的结尾。返回介于
0
请求大小之间的值可能意味着字节“当前不可用”(这到底意味着什么?)

目前它复制每个字节,如下所示
inStream
outStream
是通用的-可以是内存、磁盘或网络流(实际上还有一些)

什么是可靠的方法来确保复制除最后16个以外的所有文件?我可以考虑在inStream上使用
位置
长度
,但是有一个gotcha在上面说

如果从流派生的类不支持查找,则调用Length、SetLength、Position和Seek会抛出NotSupportedException

  • 从输入流读取1到n个字节。1

  • 将字节追加到.2

  • 将循环缓冲区中的第一个最大(0,b-16)字节写入输出流,其中b是循环缓冲区中的字节数

  • 从循环缓冲区中删除刚写入的字节

  • 转到步骤1

  • 1这就是
    Read
    方法的作用–如果调用
    int n=Read(缓冲区,0500)
    它将读取1到500个字节到
    缓冲区
    ,并返回读取的字节数。如果
    Read
    返回0,则表示您已到达流的末尾


    2为了获得最佳性能,您可以将字节直接从输入流读取到循环缓冲区中。这有点棘手,因为您必须在缓冲区底层的数组中处理换行操作。

    以下解决方案速度快且经过测试。希望有用。它使用了您已经想到的双缓冲思想编辑:简化循环,删除将第一次迭代与其余迭代分离的条件

    public static void StreamCopy(Stream inStream, Stream outStream) {
         // Define the size of the chunk to copy during each iteration (1 KiB)
         const int blockSize = 1024;
         const int bytesToOmit = 16;
    
         const int buffSize = blockSize + bytesToOmit;
    
         // Generate working buffers
         byte[] buffer1 = new byte[buffSize];
         byte[] buffer2 = new byte[buffSize];
    
         // Initialize first iteration
         byte[] curBuffer = buffer1;
         byte[] prevBuffer = null;
    
         int bytesRead;
    
         // Attempt to fully fill the buffer
         bytesRead = inStream.Read(curBuffer, 0, buffSize);
         if( bytesRead == buffSize ) {
            // We succesfully retrieved a whole buffer, we will output
            // only [blockSize] bytes, to avoid writing to the last
            // bytes in the buffer in case the remaining 16 bytes happen to 
            // be the last ones
            outStream.Write(curBuffer, 0, blockSize);
         } else {
            // We couldn't retrieve the whole buffer
            int bytesToWrite = bytesRead - bytesToOmit;
            if( bytesToWrite > 0 ) {
               outStream.Write(curBuffer, 0, bytesToWrite);
            }
            // There's no more data to process
            return;
         }
    
         curBuffer = buffer2;
         prevBuffer = buffer1;
    
         while( true ) {
            // Attempt again to fully fill the buffer
            bytesRead = inStream.Read(curBuffer, 0, buffSize);
            if( bytesRead == buffSize ) {
               // We retrieved the whole buffer, output first the last 16 
               // bytes of the previous buffer, and output just [blockSize]
               // bytes from the current buffer
               outStream.Write(prevBuffer, blockSize, bytesToOmit);
               outStream.Write(curBuffer, 0, blockSize);
            } else {
               // We could not retrieve a complete buffer 
               if( bytesRead <= bytesToOmit ) {
                  // The bytes to output come solely from the previous buffer
                  outStream.Write(prevBuffer, blockSize, bytesRead);
               } else {
                  // The bytes to output come from the previous buffer and
                  // the current buffer
                  outStream.Write(prevBuffer, blockSize, bytesToOmit);
                  outStream.Write(curBuffer, 0, bytesRead - bytesToOmit);
               }
               break;
            }
            // swap buffers for next iteration
            byte[] swap = prevBuffer;
            prevBuffer = curBuffer;
            curBuffer = swap;
         }
      }
    
    static void Assert(Stream inStream, Stream outStream) {
       // Routine that tests the copy worked as expected
             inStream.Seek(0, SeekOrigin.Begin);
             outStream.Seek(0, SeekOrigin.Begin);
             Debug.Assert(outStream.Length == Math.Max(inStream.Length - bytesToOmit, 0));
             for( int i = 0; i < outStream.Length; i++ ) {
                int byte1 = inStream.ReadByte();
                int byte2 = outStream.ReadByte();
                Debug.Assert(byte1 == byte2);
             }
    
          }
    
    publicstaticvoidstreamcopy(流内流、流外流){
    //定义每次迭代期间要复制的块的大小(1kib)
    const int blockSize=1024;
    常量int bytesToOmit=16;
    const int buffSize=blockSize+bytesToOmit;
    //生成工作缓冲区
    byte[]buffer1=新字节[buffSize];
    byte[]buffer2=新字节[buffSize];
    //初始化第一次迭代
    字节[]curBuffer=buffer1;
    字节[]prevBuffer=null;
    int字节读取;
    //尝试完全填充缓冲区
    bytesRead=流内读取(路缘缓冲区,0,buffSize);
    if(bytesRead==buffSize){
    //我们成功地检索了整个缓冲区,我们将输出
    //仅[blockSize]字节,以避免写入最后一个
    //缓冲区中的字节,以防剩余的16个字节发生错误
    //是最后一个
    outStream.Write(限制缓冲区,0,块大小);
    }否则{
    //我们无法检索整个缓冲区
    int bytesToWrite=bytesRead-bytesToOmit;
    如果(bytesToWrite>0){
    outStream.Write(corbuffer,0,bytesToWrite);
    }
    //没有更多的数据要处理
    返回;
    }
    corbuffer=buffer2;
    prevBuffer=buffer1;
    while(true){
    //再次尝试完全填充缓冲区
    bytesRead=流内读取(路缘缓冲区,0,buffSize);
    if(bytesRead==buffSize){
    //我们检索了整个缓冲区,首先输出最后16个缓冲区
    //前一个缓冲区的字节数,仅输出[blockSize]
    //当前缓冲区中的字节数
    outStream.Write(prevBuffer、blockSize、bytesToOmit);
    outStream.Write(限制缓冲区,0,块大小);
    }否则{
    //我们无法检索完整的缓冲区
    
    如果(bytesRead使用循环缓冲区听起来不错,但在.NET中没有循环缓冲区类,这意味着额外的代码。我最终使用了以下算法,一种
    映射和复制
    -我认为它很简单。为了在这里自我描述,变量名比通常的要长

    这将通过缓冲区作为


    [扩展]如果你想要一个100%可靠的方法,只需创建一个新的缓冲区,减少16个字节,并复制所有的16个字节。@Blam:inStream的范围可以从1字节到40GB左右。我有一个想法,通过对复制过程进行双缓冲,看看别人的头文件流中是否有更好的内容,但肯定不是全部,有一个方便的设置长度methody您似乎混淆了n的含义。是最大块大小、单次读取获得的字节数,还是工作缓冲区中当前的字节数?总的来说,使用循环队列的算法和建议很好,所以+1。
    
    public static void StreamCopy(Stream inStream, Stream outStream) {
         // Define the size of the chunk to copy during each iteration (1 KiB)
         const int blockSize = 1024;
         const int bytesToOmit = 16;
    
         const int buffSize = blockSize + bytesToOmit;
    
         // Generate working buffers
         byte[] buffer1 = new byte[buffSize];
         byte[] buffer2 = new byte[buffSize];
    
         // Initialize first iteration
         byte[] curBuffer = buffer1;
         byte[] prevBuffer = null;
    
         int bytesRead;
    
         // Attempt to fully fill the buffer
         bytesRead = inStream.Read(curBuffer, 0, buffSize);
         if( bytesRead == buffSize ) {
            // We succesfully retrieved a whole buffer, we will output
            // only [blockSize] bytes, to avoid writing to the last
            // bytes in the buffer in case the remaining 16 bytes happen to 
            // be the last ones
            outStream.Write(curBuffer, 0, blockSize);
         } else {
            // We couldn't retrieve the whole buffer
            int bytesToWrite = bytesRead - bytesToOmit;
            if( bytesToWrite > 0 ) {
               outStream.Write(curBuffer, 0, bytesToWrite);
            }
            // There's no more data to process
            return;
         }
    
         curBuffer = buffer2;
         prevBuffer = buffer1;
    
         while( true ) {
            // Attempt again to fully fill the buffer
            bytesRead = inStream.Read(curBuffer, 0, buffSize);
            if( bytesRead == buffSize ) {
               // We retrieved the whole buffer, output first the last 16 
               // bytes of the previous buffer, and output just [blockSize]
               // bytes from the current buffer
               outStream.Write(prevBuffer, blockSize, bytesToOmit);
               outStream.Write(curBuffer, 0, blockSize);
            } else {
               // We could not retrieve a complete buffer 
               if( bytesRead <= bytesToOmit ) {
                  // The bytes to output come solely from the previous buffer
                  outStream.Write(prevBuffer, blockSize, bytesRead);
               } else {
                  // The bytes to output come from the previous buffer and
                  // the current buffer
                  outStream.Write(prevBuffer, blockSize, bytesToOmit);
                  outStream.Write(curBuffer, 0, bytesRead - bytesToOmit);
               }
               break;
            }
            // swap buffers for next iteration
            byte[] swap = prevBuffer;
            prevBuffer = curBuffer;
            curBuffer = swap;
         }
      }
    
    static void Assert(Stream inStream, Stream outStream) {
       // Routine that tests the copy worked as expected
             inStream.Seek(0, SeekOrigin.Begin);
             outStream.Seek(0, SeekOrigin.Begin);
             Debug.Assert(outStream.Length == Math.Max(inStream.Length - bytesToOmit, 0));
             for( int i = 0; i < outStream.Length; i++ ) {
                int byte1 = inStream.ReadByte();
                int byte2 = outStream.ReadByte();
                Debug.Assert(byte1 == byte2);
             }
    
          }
    
    public byte[] CopyStreamExtractLastBytes(Stream inStream, Stream outStream,
                                             int extractByteCount)
    {
        //var mainBuf = new byte[1024*4]; // 4K buffer ok for network too
        var mainBuf = new byte[4651]; // nearby prime for testing
    
        int mainBufValidCount;
        var tailBuf = new byte[extractByteCount];
        int tailBufValidCount = 0;
    
        while ((mainBufValidCount = inStream.Read(mainBuf, 0, mainBuf.Length)) > 0)
        {
            // Map: how much of what (passthru/tail) lives where (MainBuf/tailBuf)
            // more than tail is passthru
            int totalPassthruCount = Math.Max(0, tailBufValidCount + 
                                        mainBufValidCount - extractByteCount);
            int tailBufPassthruCount = Math.Min(tailBufValidCount, totalPassthruCount);
            int tailBufTailCount = tailBufValidCount - tailBufPassthruCount;
            int mainBufPassthruCount = totalPassthruCount - tailBufPassthruCount;
            int mainBufResidualCount = mainBufValidCount - mainBufPassthruCount;
    
            // Copy: Passthru must be flushed per FIFO order (tailBuf then mainBuf)
            outStream.Write(tailBuf, 0, tailBufPassthruCount);
            outStream.Write(mainBuf, 0, mainBufPassthruCount);
    
            // Copy: Now reassemble/compact tail into tailBuf
            var tempResidualBuf = new byte[extractByteCount];
            Array.Copy(tailBuf, tailBufPassthruCount, tempResidualBuf, 0, 
                          tailBufTailCount);
            Array.Copy(mainBuf, mainBufPassthruCount, tempResidualBuf, 
                          tailBufTailCount, mainBufResidualCount);
            tailBufValidCount = tailBufTailCount + mainBufResidualCount;
            tailBuf = tempResidualBuf;
        }
        return tailBuf;
    }