【问题标题】:C# partial UTF-8 byte stream conversionC# 部分 UTF-8 字节流转换
【发布时间】:2015-01-10 02:41:22
【问题描述】:

我写了以下简单的测试:

[Test]
public void TestUTF8()
{
    var c = "abc☰def";
    var b = Encoding.UTF8.GetBytes(c);

    Assert.That(b.Length, Is.EqualTo(9));
    //Assuming, you are reading a byte stream and got partial result with the first 5 bytes
    var p = Encoding.UTF8.GetChars(b, 0, 5);
    Trace.WriteLine(new string(p));
    Assert.That(p.Length, Is.EqualTo(3));
}

Trace 输出abc�,最后一个断言失败,因为p.Length4

但是,我想要 Trace 输出 abc 并且最后一个断言通过,因为实际上我知道流将具有有效字符,并且当最后几个字节不是这种情况时,只需将它们留在那里等待更多数据即将到来。

那么如何在 C# 中实现这一点?

【问题讨论】:

  • 我相信这就是GetChars 的工作原理。它专为完整输入而设计。如果您正在解码流,建议您使用 Decoder.Convert 而不是 GetChars 正是出于这个原因。在这种情况下,解码器是从Encoding.UTF8.GetDecoder 获得的。
  • 你是对的......使用GetChars只是因为它很简单......所以如果我们必须使用更复杂的函数也可以。你能回答这个建议吗?
  • @EarthEngine:在这里查看我的答案:stackoverflow.com/questions/26844999/… 那里的 OP 似乎已经决定使用 BinaryReader (实际上可能也一样,因为他们只想在一次),但我的回答显示了如何在不太抽象的级别上实现该行为,并且可以很容易地适应一次读取任意长度的缓冲区。
  • @PeterDuniho 好电话。 Decoder.GetChars 似乎更容易使用。在我的回答中,我已将您的样本扩展到任意缓冲区大小。
  • @EarthEngine 好的,我得到了一个基于Decoder.GetChars 的答案,它比Decoder.Convert 更易于使用。

标签: c# utf-8 character-encoding


【解决方案1】:

Encoding.GetChars 并不是真正为来自流的字节设计的,在解码过程中需要跟踪某些状态,因为单个字符可能跨越多个缓冲区段。要完成这项工作,您应该使用从Encoding.GetDecoder 获得的Decoder。但是,Decoder.Convert 确实是低级的,允许您控制输入和输出缓冲区,并且有点难以使用。 Decoder.GetChars 更易于使用,并且负责在调用之间存储状态的重要工作。我们可以轻松扩展 Peter Duniho 的 answer 以获得任意缓冲区大小:

public static void Main(string[] args)
{
    var c = "abc☰def";
    var b = Encoding.UTF8.GetBytes(c);
    var result = DecodeFromStream(new MemoryStream(b), Encoding.UTF8, 3);
    Console.WriteLine(result);
    Console.WriteLine(c == result);
}

private static string DecodeFromStream(Stream dataStream, Encoding encoding, int bufferSize)
{
    Decoder decoder = encoding.GetDecoder();
    StringBuilder sb = new StringBuilder();
    int inputByteCount;
    byte[] inputBuffer = new byte[bufferSize];
    char[] charBuffer = new char[encoding.GetMaxCharCount(inputBuffer.Length)];

    while ((inputByteCount = dataStream.Read(inputBuffer, 0, inputBuffer.Length)) > 0)
    {                   
       int readChars = decoder.GetChars(inputBuffer, 0, inputByteCount, charBuffer, 0);
       if (readChars > 0)
           sb.Append(charBuffer, 0, readChars);
    }
    return sb.ToString();
}

【讨论】:

    猜你喜欢
    • 2015-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多