将字符串作为流读取而不复制

问题描述 投票:-1回答:3

我在字符串中有一些数据。我有一个函数,它将流作为输入。我想将我的数据提供给我的函数,而不必将完整的字符串复制到流中。基本上我正在寻找一个可以包装字符串并从中读取的流类。

我在网上看到的唯一建议是建议不是流的StringReader,或者创建一个内存流并写入它,这意味着复制数据。我可以编写自己的流对象,但棘手的部分是处理编码,因为流以字节为单位进行处理。有没有办法在不编写新流类的情况下执行此操作?

我正在BizTalk中实现管道组件。 BizTalk完全使用流来处理所有内容,因此您总是将内容传递给BizTalk。 BizTalk将始终以小块读取该流,因此将整个字符串复制到流中是没有意义的(特别是如果字符串很大),如果我可以从流中读取BizTalk想要它。

c# .net c#-4.0 biztalk biztalk-2013
3个回答
1
投票

您可以防止必须维护整个事物的副本,但是您将被迫使用对每个字符产生相同字节数的编码。这样你可以通过Encoding.GetBytes(str, strIndex, byteCount, byte[], byteIndex)提供数据块,因为它们被直接请求到读缓冲区。

每个Stream.Read()操作总会有一个复制操作,因为它允许调用者提供目标缓冲区。


1
投票

这是一个适当的StringReaderStream有以下缺点:

  • Read的缓冲区必须至少为maxBytesPerChar。通过保持内部一个char Read,可以为小缓冲区实现buff = new byte[maxBytesPerChar]。但对大多数用法来说并不是必需的。
  • 没有Seek,它可以做寻求,但通常会非常棘手。 (有些寻求案例,如寻求开始,寻求结束,实施起来很简单。)
/// <summary>
/// Convert string to byte stream.
/// <para>
/// Slower than <see cref="Encoding.GetBytes()"/>, but saves memory for a large string.
/// </para>
/// </summary>
public class StringReaderStream : Stream
{
    private string input;
    private readonly Encoding encoding;
    private int maxBytesPerChar;
    private int inputLength;
    private int inputPosition;
    private readonly long length;
    private long position;

    public StringReaderStream(string input)
        : this(input, Encoding.UTF8)
    { }

    public StringReaderStream(string input, Encoding encoding)
    {
        this.encoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
        this.input = input;
        inputLength = input == null ? 0 : input.Length;
        if (!string.IsNullOrEmpty(input))
            length = encoding.GetByteCount(input);
            maxBytesPerChar = encoding == Encoding.ASCII ? 1 : encoding.GetMaxByteCount(1);
    }

    public override bool CanRead => true;

    public override bool CanSeek => false;

    public override bool CanWrite => false;

    public override long Length => length;

    public override long Position
    {
        get => position;
        set => throw new NotImplementedException();
    }

    public override void Flush()
    {
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        if (inputPosition >= inputLength)
            return 0;
        if (count < maxBytesPerChar)
            throw new ArgumentException("count has to be greater or equal to max encoding byte count per char");
        int charCount = Math.Min(inputLength - inputPosition, count / maxBytesPerChar);
        int byteCount = encoding.GetBytes(input, inputPosition, charCount, buffer, offset);
        inputPosition += charCount;
        position += byteCount;
        return byteCount;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotImplementedException();
    }

    public override void SetLength(long value)
    {
        throw new NotImplementedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        throw new NotImplementedException();
    }
}

-1
投票

Stream只能复制数据。此外,它处理bytes,而不是chars,所以你必须通过解码过程复制数据。但是,如果要将字符串视为ASCII字节流,可以创建一个实现Stream的类来执行此操作。例如:

public class ReadOnlyStreamStringWrapper : Stream
{
    private readonly string theString;

    public ReadOnlyStreamStringWrapper(string theString)
    {
        this.theString = theString;
    }

    public override void Flush()
    {
        throw new NotSupportedException();
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        switch (origin)
        {
            case SeekOrigin.Begin:
                if(offset < 0 || offset >= theString.Length)
                    throw new InvalidOperationException();

                Position = offset;
                break;
            case SeekOrigin.Current:
                if ((Position + offset) < 0)
                    throw new InvalidOperationException();
                if ((Position + offset) >= theString.Length)
                    throw new InvalidOperationException();

                Position += offset;
                break;
            case SeekOrigin.End:
                if ((theString.Length + offset) < 0)
                    throw new InvalidOperationException();
                if ((theString.Length + offset) >= theString.Length)
                    throw new InvalidOperationException();
                Position = theString.Length + offset;
                break;
        }

        return Position;
    }

    public override void SetLength(long value)
    {
        throw new NotSupportedException();
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return Encoding.ASCII.GetBytes(theString, (int)Position, count, buffer, offset);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        throw new NotSupportedException();
    }

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanSeek
    {
        get { return true; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override long Length
    {
        get { return theString.Length; }
    }

    public override long Position { get; set; }
}

但是,避免“复制”数据需要做很多工作......

© www.soinside.com 2019 - 2024. All rights reserved.