将byte []编码为String

max*_*ann 6 java encoding byte utf-8 character-encoding

Heyho,

我想将字节数据(可以是任何东西)转换为字符串.我的问题是,用UTF-8编码字节数据是否"安全",例如:

String s1 = new String(data, "UTF-8");
Run Code Online (Sandbox Code Playgroud)

或者使用base64:

String s2 = Base64.encodeToString(data, false); //migbase64
Run Code Online (Sandbox Code Playgroud)

我只是担心使用第一种方法会产生负面影响.我的意思是两个变体都可以运行,但是s1可以包含UTF-8字符集的任何字符,s2只使用"可读"字符.我只是不确定是否真的需要使用base64.基本上我只需要创建一个String,通过网络发送它并再次接收它.(在我的情况下没有别的办法:/)

问题只是消极的副作用,如果可能的话!

Jon*_*eet 17

绝对应该使用base64或者hex.(要么工作; base64更紧凑,但人类更难阅读.)

你声称"两种变体都能完美地工作",但事实并非如此.如果您使用第一种方法并且data实际上不是有效的UTF-8序列,则会丢失数据.您不是要尝试将UTF-8编码的文本转换为a String,因此请勿编写尝试执行此操作的代码.

使用ISO-8859-1作为编码将保留所有数据 - 但在很多情况下,返回的字符串将不容易通过其他协议传输.例如,它可能包含不可打印的控制字符.

只有String(byte[], String)在拥有固有的文本数据时才使用构造函数,而这恰好是编码形式的数据(编码被指定为第二个参数).对于其他任何东西 - 例如音乐,视频,图像,加密或压缩数据 - 你应该使用一种方法,将输入数据视为"任意二进制数据",并找到它的文本编码......这正是base64和十六进制.

  • @ p000ison UTF-8不会在每个组合中使用每个可能的字节值,这意味着某些组合无效.有些组合产生与其他组合相同的`char`,这意味着无法确定原始byte []是什么. (2认同)
  • @PeterLawrey:我认为UTF-8不允许对单个字符进行多次有效编码.来自维基百科:"该标准规定了代码点的正确编码仅使用保存代码点的有效位所需的最小字节数.较长的编码被称为过长并且不是代码点的有效UTF-8表示". (2认同)

Pet*_*rey 5

你可以在String中存储一个字节,虽然这不是一个好主意.您不能使用UTF-8,因为这将管理字节,但更快更有效的方法是使用ISO-8859-1编码或普通的8位.最简单的方法是使用

String s1 = new String(data, 0);
Run Code Online (Sandbox Code Playgroud)

要么

String s1 = new String(data, "ISO-8859-1");
Run Code Online (Sandbox Code Playgroud)

来自维基百科上的UTF-8,如Jon Skeet所述,这些编码在标准下无效.他们在Java中的行为各不相同 DataInputStream将前三个版本视为相同,后两个抛出异常.Charset解码器默默地将它们视为单独的字符.

00000000 is \0
11000000 10000000 is \0
11100000 10000000 10000000 is \0
11110000 10000000 10000000 10000000 is \0
11111000 10000000 10000000 10000000 10000000 is \0
11111100 10000000 10000000 10000000 10000000 10000000 is \0
Run Code Online (Sandbox Code Playgroud)

这意味着如果在String中看到\ 0,则无法确定原始byte []值是什么.DataOutputStream使用第二个选项与C兼容,将C视为终止符.

BTW DataOutputStream不知道代码点,因此以UTF-16编写高代码点字符,然后写入UTF-8编码.

0xFE和0xFF无效出现在字符中.值0x11000000 +只能出现在字符的开头,而不能出现在多字节字符内.