Я написал вам быстрый маленький поток, который буферизует вперед на 20 байтов. Единственная реальная реализация, которую я переопределил должным образом, - это член Read()
, возможно, вам придется изучить другие члены Stream
в соответствии с вашим делом. Поставляется с бесплатным тестовым классом тоже! Бонус! Я проверил это более тщательно, но вы можете адаптировать эти тестовые примеры к своей воле. Да, и, кстати, я не тестировал его для потоков длиной менее 20 байт.
Контрольный пример
[TestClass]
public class TruncateStreamTests
{
[TestMethod]
public void TestTruncateLast20Bytes()
{
string testInput = "This is a string.-- final 20 bytes --";
string expectedOutput = "This is a string.";
string testOutput;
using (var testStream = new StreamWhichEndsBeforeFinal20Bytes(new MemoryStream(Encoding.ASCII.GetBytes(testInput))))
using (var streamReader = new StreamReader(testStream, Encoding.ASCII))
{
testOutput = streamReader.ReadLine();
}
Assert.AreEqual(expectedOutput, testOutput);
}
[TestMethod]
public void TestTruncateLast20BytesRead3BytesAtATime()
{
string testInput = "This is a really really really really really long string, longer than all the others\n\rit even has some carriage returns in it, etc.-- final 20 bytes --";
string expectedOutput = "This is a really really really really really long string, longer than all the others\n\rit even has some carriage returns in it, etc.";
StringBuilder testOutputBuilder = new StringBuilder();
using (var testStream = new StreamWhichEndsBeforeFinal20Bytes(new MemoryStream(Encoding.ASCII.GetBytes(testInput))))
{
int bytesRead = 0;
do
{
byte[] buffer = new byte[3];
bytesRead = testStream.Read(buffer, 0, 3);
testOutputBuilder.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead));
} while (bytesRead > 0);
}
Assert.AreEqual(expectedOutput, testOutputBuilder.ToString());
}
}
Потоковый класс
public class StreamWhichEndsBeforeFinal20Bytes : Stream
{
private readonly Stream sourceStream;
private static int TailBytesCount = 20;
public StreamWhichEndsBeforeFinal20Bytes(Stream sourceStream)
{
this.sourceStream = sourceStream;
}
public byte[] TailBytes { get { return previousTailBuffer; } }
public override void Flush()
{
sourceStream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return sourceStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
sourceStream.SetLength(value);
}
private byte[] previousTailBuffer;
public override int Read(byte[] buffer, int offset, int count)
{
byte[] tailBuffer = new byte[TailBytesCount];
int expectedBytesRead;
if (previousTailBuffer == null)
expectedBytesRead = count + TailBytesCount;
else
expectedBytesRead = count;
try
{
byte[] readBuffer = new byte[expectedBytesRead];
int actualBytesRead = sourceStream.Read(readBuffer, offset, expectedBytesRead);
if (actualBytesRead == 0) return 0;
if (actualBytesRead < TailBytesCount)
{
int pickPreviousByteCount = TailBytesCount - actualBytesRead;
if (previousTailBuffer != null)
{
int pickFromIndex = previousTailBuffer.Length - pickPreviousByteCount;
Array.Copy(previousTailBuffer, 0, buffer, offset, count);
Array.Copy(previousTailBuffer, pickFromIndex, tailBuffer, 0, pickPreviousByteCount);
}
Array.Copy(readBuffer, 0, tailBuffer, pickPreviousByteCount, actualBytesRead);
return actualBytesRead;
}
Array.Copy(readBuffer, actualBytesRead - TailBytesCount, tailBuffer, 0, TailBytesCount);
Array.Copy(readBuffer, 0, buffer, offset, actualBytesRead - TailBytesCount);
if (actualBytesRead < expectedBytesRead)
{
return actualBytesRead - TailBytesCount;
}
return count;
}
finally
{
previousTailBuffer = tailBuffer;
}
}
public override void Write(byte[] buffer, int offset, int count)
{
sourceStream.Write(buffer, offset, count);
}
public override bool CanRead
{
get { return sourceStream.CanRead; }
}
public override bool CanSeek
{
get { return sourceStream.CanSeek; }
}
public override bool CanWrite
{
get { return sourceStream.CanWrite; }
}
public override long Length
{
get
{
if (sourceStream.Length < TailBytesCount) return sourceStream.Length;
return sourceStream.Length - TailBytesCount;
}
}
public override long Position
{
get { return sourceStream.Position; }
set { sourceStream.Position = value; }
}
}