在.NET中为什么不是这样:
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(x))
返回任意字节数组x
的原始字节数组?
回答另一个问题是mentioned,但响应者没有解释原因。
答案 0 :(得分:3)
首先,正如watbywbarif所提到的,你不应该使用==
比较序列,这不起作用。
但即使您正确地比较数组(例如使用SequenceEquals()
或只是通过查看它们),它们并不总是相同。可能发生这种情况的一种情况是x
是无效的UTF-8编码字符串。
例如,0xFF
的1字节序列无效UTF-8。那么Encoding.UTF8.GetString(new byte[] { 0xFF })
会返回什么?它是 ,U + FFFD,替换字符。当然,如果你打电话给Encoding.UTF8.GetBytes()
,它就不会回复0xFF
。
答案 1 :(得分:1)
字符编码(特定于UTF8)对于相同的代码点可能具有不同的形式。
因此,当您转换为字符串并返回时,实际字节可能表示不同(规范)形式。
另见String.Normalize(NormalizationForm.System.Text.NormalizationForm.FormD)
另见:
某些Unicode序列被认为是等效的,因为它们代表相同的字符。例如,以下内容被认为是等效的,因为其中任何一个都可用于表示“ắ”:
"\u1EAF" "\u0103\u0301" "\u0061\u0306\u0301"
但是,序数(即二进制)比较认为这些序列不同,因为它们包含不同的Unicode代码值。在执行序数比较之前,应用程序必须对这些字符串进行规范化,以将它们分解为基本组件。
该页面附带了一个很好的示例,可以显示哪些编码始终被标准化
答案 2 :(得分:1)
这是因为==不会比较数组的每个元素。它与Encoding.UTF8无关。 检查一下:
var a = new byte[] { 1 };
var b = new byte[] { 1 };
bool res = a == b;
答案 3 :(得分:1)
另一个角度来看,Encoding
类 设计用于往返数据,但它们设计为往返的数据为{{1}数据,编码为char
,而不是相反。这意味着,在所讨论的byte
的功能范围内,每个Encoding
值都有char
值(1或更多)的相应编码,这些值将变回完全相同的byte
值。char
(值得注意的是,并非所有Encoding
都能为所有可能的char
值执行此操作 - 例如,Encoding.ASCII
只能支持char
[0, 128)
范围内的值。)
因此,如果您从字符数据开始,并且需要一种方法来存储或发送它在一个使用字节的媒介(例如磁盘上的文件或网络流),Encoding
是一个将char
数据转换为byte
数据然后在另一端再次转换的绝佳方法。 (如果要支持所有可能的字符串,则需要使用基于Unicode的Encoding
之一,例如Encoding.Unicode
或Encoding.UTF8
。 )
那么,如果你从一堆byte
开始,这意味着什么呢?好吧,根据所讨论的编码,您正在使用的byte
实际上可能不是Encoding
输出的序列。您需要将Encoding.GetBytes
视为编码操作,并将Encoding.GetChars
/ Encoding.GetString
视为解码操作,因此您需要重新开始使用任意数组的字节并尝试解码它们。
要进行类比,请考虑图像的JPEG文件格式。这具有类似类型的编码和解码,其中在这种情况下,解码数据不是string
而是图像。那么,如果你采用任意字节串,那么它可以被解码为JPEG图像的几率是多少?显然,答案非常渺茫。更有可能的是,你的字节最终将沿着解码器中的一条路径走下去,“在那里,我不希望那个字节跟在另一个之后”,并且它将尽力处理假设数据它是一个有效的JPEG文件,以某种方式受损。
将任意字节数组转换为字符串时,会发生同样的事情。 UTF-8编码具有关于如何char
值128及以上编码的特定规则,其中一条规则表明在匹配a之后,您将只看到与位模式10xxxxxx
匹配的字节类似110xxxxx
,1110xxxx
或11110xxx
的模式,它“引入”多字节序列(多个byte
代表单个char
)。因此,如果您的数据包含与模式10xxxxxx
匹配的字节,不遵循预期的“引入者”之一,则编码器只能假设数据以某种方式受损。它有什么作用?它插入了一个字符,上面写着“编码数据出现了严重错误。我尽力了。这就是出错的地方。”设计Unicode的人预测了这个确切的场景,并创建了一个具有这个精确含义的角色:Replacement Character。
因此,如果您尝试在byte
字符串中对char
进行往返并且遇到此情况,那么违规byte
的实际值就会丢失,而是插入替换字符。当您尝试将string
转回byte
数组时,它最终会编码替换字符,而不是原始数据。原始数据丢失。
您正在寻找的是编码&在另一个方向上工作的解码关系。 Encoding
用于获取char
数据,并找到将其临时存储为byte
数据的方法。如果您想要获取byte
数据并找到将其临时存储为char
数据的方法,则需要为此特定目的设计编码。幸运的是,这些存在。维基百科有fairly comprehensive list个选项。 : - )
在.NET Framework中,最简单且最易于访问的选项是MIME Base-64编码,通过Convert.ToBase64String
和Convert.FromBase64String
公开。