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