如何高效地用流包装字符串(在.NET中)
本文关键字:字符串 包装 NET 何高效 高效 | 更新日期: 2023-09-27 18:26:12
关于将字符串转换为流的问题很多,例如:
- 将字符串转换为流
- 如何从字符串生成流
- 将字符串转换为System.IO.Stream
还有很多其他的。
然而,我还没有看到一个不会复制原始字符串占用的内存的实现。最简单的建议是将字符串转换为字节,并从中初始化MemoryStream
另一个建议是将其写入封装MemoryStream
的StreamWriter
中
它们并非都是高效记忆的。
我之所以带它来,是因为我必须处理一个纯粹愚蠢的遗留系统,它会产生一根巨大的绳子。现在,我需要对这个字符串进行某些后期处理,并将其写入文件,我只是不想重复这个该死的东西。因此,我正在寻找一种内存高效的方法。
编写一个自定义的Stream
派生类并不困难,但在这种特殊情况下,具有挑战性的部分是需要Encoding
支持。这里有一个只读前向实现,它在需要时使用一个小缓冲区来容纳一个完整的字符字节:
public static class StringUtils
{
public static Stream AsStream(this string source, Encoding encoding = null)
{
return string.IsNullOrEmpty(source) ? Stream.Null : new StringStream(source, encoding ?? Encoding.UTF8);
}
class StringStream : Stream
{
string source;
Encoding encoding;
int position, length;
int charPosition;
int maxBytesPerChar;
byte[] encodeBuffer;
int encodeOffset, encodeCount;
internal StringStream(string source, Encoding encoding)
{
this.source = source;
this.encoding = encoding;
length = encoding.GetByteCount(source);
maxBytesPerChar = encoding.GetMaxByteCount(1);
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return length; } }
public override void SetLength(long value) { throw new NotSupportedException(); }
public override long Position { get { return position; } set { throw new NotSupportedException(); } }
public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count)
{
int readCount = 0;
for (int byteCount; readCount < count && position < length; position += byteCount, readCount += byteCount)
{
if (encodeCount == 0)
{
int charCount = Math.Min((count - readCount) / maxBytesPerChar, source.Length - charPosition);
if (charCount > 0)
{
byteCount = encoding.GetBytes(source, charPosition, charCount, buffer, offset + readCount);
Debug.Assert(byteCount > 0 && byteCount <= (count - readCount));
charPosition += charCount;
continue;
}
if (encodeBuffer == null) encodeBuffer = new byte[maxBytesPerChar];
encodeCount = encoding.GetBytes(source, charPosition, 1, encodeBuffer, encodeOffset = 0);
Debug.Assert(encodeCount > 0);
}
byteCount = Math.Min(encodeCount, count - readCount);
for (int i = 0; i < byteCount; i++)
buffer[offset + readCount + i] = encodeBuffer[encodeOffset + i];
encodeOffset += byteCount;
if ((encodeCount -= byteCount) == 0) charPosition++;
}
return readCount;
}
}
}