我应该在 .NET 中使用 UTF8 编码字符串做什么?

What am I supposed to do in .NET with a UTF8 Encoded string?

我正在使用 Google Chrome 本机消息,它说它提供 UTF8 编码 JSON。 Found here.

我很确定我的代码相当标准,并且几乎是 C# 中答案的副本。

Private Function OpenStandardStreamIn() As String
    Dim MsgLength As Integer = 0
    Dim InputData As String = ""
    Dim LenBytes As Byte() = New Byte(3) {} 'first 4 bytes are length

    Dim StdIn As System.IO.Stream = Console.OpenStandardInput() 'open the stream
    StdIn.Read(LenBytes, 0, 4) 'length
    MsgLength = System.BitConverter.ToInt32(LenBytes, 0) 'convert length to Int

    Dim Buffer As Char() = New Char(MsgLength - 1) {} 'create Char array for remaining bytes

    Using Reader As System.IO.StreamReader = New System.IO.StreamReader(StdIn) 'Using to auto dispose of stream reader
        While Reader.Peek() >= 0 'while the next byte is not Null
            Reader.Read(Buffer, 0, Buffer.Length) 'add to the buffer
        End While
    End Using

    InputData = New String(Buffer) 'convert buffer to string

    Return InputData
End Function

我遇到的问题是,当 JSON 包含 ß Ü Ö Ä 等字符时,整个字符串似乎不同,我无法反序列化它。它是可读的,我的日志显示字符串很好,但有一些不同。只要字符串不包含这些字符,反序列化就可以正常工作。我没有提供 JavascriptSerializer 代码,因为这不是问题所在。

我尝试使用不同的编码创建 StreamReader,例如

New System.IO.StreamReader(StdIn, Encoding.GetEncoding("iso-8859-1"), True)

但是 ß Ä 等不正确。

我不明白的是,如果字符串是 UTF8 而 .NET 使用 UTF16,我应该如何确保转换正确完成?

更新

一直在做一些测试。我发现如果我收到一个带有 fuß 的字符串,则消息长度(由本机消息传递提供)为 4,但缓冲区中的字符数为 3,如果字符串为 fus,则消息长度为 3,字符数为3. 为什么会这样?

对于上面的代码,Buffer 对象 1 太大,这就是出现问题的原因。如果我简单地在流上使用 Read 方法,那么它就可以正常工作。 Google 消息发送的消息长度似乎与字符串中的 ß 不同。

如果我想使用上面的代码,我怎么知道消息长度不对?

如果您在控制台中显示这段代码的输出,这很可能会发生。因为 windows 控制台不显示 Unicode 字符。如果不是这种情况,则尝试使用字符串生成器将 StdIn 流中的数据转换为字符串

"Each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB." 这意味着消息长度以字节为单位,而且长度不是消息的一部分(因此它的长度不包括在长度中)。

您的困惑似乎源于以下两件事之一:

  1. UTF-8 以 1 到 4 个代码单元对 Unicode 代码点进行编码。 (一个UTF-8编码单元是8位,一个字节。)
  2. Char 是一个 UTF-16 编码单元。 (一个UTF-16编码单元是16位,两个字节。UTF-16以1到2个编码单元编码一个Unicode代码点。)

在转换(或扫描,但您也可以直接转换)之前,无法判断消息中有多少代码点或 UTF-16 代码单元。

然后,据推测,stream 要么被发现已关闭,要么接下来要阅读的内容将是另一个长度和消息。

所以,

Private Iterator Function Messages(stream As Stream) As IEnumerable(Of String)
    Using reader = New BinaryReader(stream)
        Try                
            While True
                Dim length = reader.ReadInt32
                Dim bytes = reader.ReadBytes(length)
                Dim message = Encoding.UTF8.GetString(bytes)
                Yield message
            End While
        Catch e As EndOfStreamException
            ' Expected when the sender is done
            Return
        End Try
    End Using
End Function

用法

Messages(stream).ToList()

For Each message In Messages(stream)
    Debug.WriteLine(message)            
Next message