字节数组转换成字符串,在把字符串转换成字节数组,为什么数据损坏了?

西夏一品堂 发布于 2017/10/08 12:16
阅读 889
收藏 0

byte[] data = Files.readAllBytes(Paths.get("/tmp/apache-tomcat-7.0.82.zip"));
这里有个字节数组,我先把这个字节数字转换成字符串,

String str = new String(data);
然后,再把这个字符串转换成字节数组

byte[] body = str.getBytes();

然后把body字节数组保存成文件,这个文件为什么是损坏的。
也就是说,为什么把字节数组转换成字符串,在把字符串转换成字节数组,就变了。
 

加载中
0
polly
polly

看着楼上乱猜,捉急。建议还是看看原理,再来说。举一个简单的例子,zip文件是二进制流,这是前提,没问题吧?

假设楼主的环境是UTF8,一般都是这样,这个假设应该问题不大,因为GBK也是同样的道理。

继续假设,zip文件是3个字节,用UTF8字符集String str = new String(data);然后在getBytes(),这没问题

再假设,zip文件是5个字节,问题来了。看看 String str = new String(data);做了什么?

zip字节流:AA BB CC DD EE

首先会按照utf8规则分组:[AA BB CC] [DD EE ??]

第一个汉字没问题,第二个汉字,UTF8发现不认识,他会用一个占位符"U+FFFD" 来替换掉,而这个占位符用UTF8的编码是\xef\xbf\xbd,那么分组的字节码就变成了:

[AA BB CC] [EF BF BD]

可以想象,你再getBytes() 的时候,还能还原回去吗?

关于占位符"U+FFFD" 再参考我的另一个笔记:https://my.oschina.net/polly/blog/890120

1
polly
polly
前段时间刚写了个笔记,请参阅 https://my.oschina.net/polly/blog/1523584 字节转ISO8859-1,随便转,转其他的如utf8或gbk,均有可能乱码
0
根号7
根号7

道理很明白,此处你使用了压缩文件进行读取。压缩流需要进行解压... 解压之后才能读取的。

0
Lohanry
Lohanry

应该是读取的字节数组中包含\0,在转String后,\0后的数据被截断了,然后再String转字节数组就出错了。

0
西夏一品堂
西夏一品堂

引用来自“polly”的评论

看着楼上乱猜,捉急。建议还是看看原理,再来说。举一个简单的例子,zip文件是二进制流,这是前提,没问题吧?

假设楼主的环境是UTF8,一般都是这样,这个假设应该问题不大,因为GBK也是同样的道理。

继续假设,zip文件是3个字节,用UTF8字符集String str = new String(data);然后在getBytes(),这没问题

再假设,zip文件是5个字节,问题来了。看看 String str = new String(data);做了什么?

zip字节流:AA BB CC DD EE

首先会按照utf8规则分组:[AA BB CC] [DD EE ??]

第一个汉字没问题,第二个汉字,UTF8发现不认识,他会用一个占位符"U+FFFD" 来替换掉,而这个占位符用UTF8的编码是\xef\xbf\xbd,那么分组的字节码就变成了:

[AA BB CC] [EF BF BD]

可以想象,你再getBytes() 的时候,还能还原回去吗?

关于占位符"U+FFFD" 再参考我的另一个笔记:https://my.oschina.net/polly/blog/890120

统一用unicode为啥也不行

public static void main(String[] args) throws Exception {
		String charset = "unicode";
		byte[] data = Files.readAllBytes(Paths.get("e:/tmp/1.xlsx"));
		String str = new String(data, charset);
		Files.write(Paths.get("e:/tmp/2.xlsx"), str.getBytes(charset));
	}

2.xlsx打不开,提示文件已损坏

polly
polly
Files.write(Paths.get("e:/tmp/2.xlsx"), data); //直接写byte[] 不要转码
0
polly
polly

一样的,涉及到转码,只有ISO-8859-1单纯

还有一个题外话,你保存文件,没必要用String呀,直接存byte[] 更靠谱,效率更高,因为不需要多转一次

 

返回顶部
顶部