我应该在 .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." 这意味着消息长度以字节为单位,而且长度不是消息的一部分(因此它的长度不包括在长度中)。
您的困惑似乎源于以下两件事之一:
- UTF-8 以 1 到 4 个代码单元对 Unicode 代码点进行编码。 (一个UTF-8编码单元是8位,一个字节。)
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
我正在使用 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." 这意味着消息长度以字节为单位,而且长度不是消息的一部分(因此它的长度不包括在长度中)。
您的困惑似乎源于以下两件事之一:
- UTF-8 以 1 到 4 个代码单元对 Unicode 代码点进行编码。 (一个UTF-8编码单元是8位,一个字节。)
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