【问题标题】:How to wrap a string with a stream EFFICIENTLY (in .NET)? [duplicate]如何有效地用流包装字符串(在.NET中)? [复制]
【发布时间】:2016-03-13 14:48:45
【问题描述】:

字符串转流的问题很多,例如:

还有很多其他的。

但是,我还没有看到不复制原始字符串占用的内存的实现。最简单的建议是将字符串转换为字节并从中初始化MemoryStream

另一个建议是将其写入StreamWriter 包装MemoryStream

所有这些都不是内存效率。

我带来它的原因是我必须处理一个遗留系统,它纯粹出于愚蠢而产生了一个巨大的字符串。现在我需要对该字符串应用某些后期处理并将其写入文件,我只是不想复制该死的东西。所以,我正在寻找一种内存高效的方法来做到这一点。

【问题讨论】:

  • 流需要支持哪些操作?只是Read 还是你也需要Seek?我认为不是Write(并且对您的问题中建议的StreamWriter 感到惊讶),因为字符串是不可变的。
  • 有一个StringReader,虽然它不是Stream,但它支持“流式”操作。
  • 只读。我更喜欢Stream,因为它更适合二进制转换。
  • 为什么不使用 String.SubString 重复提取字符串中合理大小的部分,然后对它们进行后处理。
  • 编码怎么样?我的意思是,字符串可以通过多种不同的方式转换为字节(因此是流)。

标签: c# string stream


【解决方案1】:

编写自定义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;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-09
    • 2012-10-05
    • 1970-01-01
    • 2021-11-03
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 2014-11-01
    相关资源
    最近更新 更多