[toc]java
小师妹学JavaIO之:文件编码和字符集Unicodegit
小师妹一时兴起,使用了一项历来都没用过的新技能,没想却出现了一个没法解决的问题。把大象装进冰箱到底有几步?乱码的问题又是怎么解决的?快来跟F师兄一块儿看看吧。程序员
更多精彩内容且看:github
这天,小师妹心情很愉悦,吹着口哨唱着歌,标准的45度俯视让人好不自在。编程
小师妹呀,什么事情这么高兴,说出来让师兄也沾点喜庆?架构
小师妹:F师兄,最新我发现了一种新型的读取文件的方法,很好用的,就跟map同样:编程语言
public void usePropertiesFile() throws IOException { Properties configProp = new Properties(); InputStream in = this.getClass().getClassLoader().getResourceAsStream("www.flydean.com.properties"); configProp.load(in); log.info(configProp.getProperty("name")); configProp.setProperty("name", "www.flydean.com"); log.info(configProp.getProperty("name")); }
F师兄你看,我使用了Properties来读取文件,文件里面的内容是key=value形式的,在作配置文件使用的时候很是恰当。我是从Spring项目中的properties配置文件中获得的灵感,才发现原来java还有一个专门读取属性文件的类Properties。工具
小师妹如今都会抢答了,果真青出于蓝。区块链
小师妹你作得很是好,就这样举一反三,很快java就要尽归你手了,后面的什么scala,go,JS等估计也通通不在话下。再过几年你就能够升任架构师,公司技术在你的带领之下必定会蒸蒸日上。测试
作为师兄,最大的责任就是给小师妹以鼓励和信心,给她描绘美好的将来,什么出任CEO,赢取高富帅等全都不在话下。据说有个专业的词汇来描述这个过程叫作:画饼。
小师妹有点心虚:但是F师兄,我还有点小小的问题没有解决,有点中文的小小乱码....
我深有体会的点点头:马赛克是阻碍人类进步的绊脚石...哦,不是马赛克,是文件乱码,要想弄清楚这个问题,还要从那个字符集和文件编码讲起。
在好久好久之前,师兄我都尚未出生的时候,西方世界出现了一种叫作计算机的高科技产品。
初代计算机只能作些简单的算数运算,还要使用人工打孔的程序才能运行,不过随着时间的推移,计算机的体积愈来愈小,计算能力愈来愈强,打孔已经不存在了,编程了人工编写的计算机语言。
一切都在变化,惟有一件事情没有变化。这件事件就是计算机和编程语言只流传在西方。而西方平常交流使用26个字母加有限的标点符号就够了。
最初的计算机存储能够是很是昂贵的,咱们用一个字节也就是8bit来存储全部可以用到的字符,除了最开始的1bit不用之外,总共有128中选择,装26个小写+26个大写字母和其余的一些标点符号之类的彻底够用了。
这就是最初的ASCII编码,也叫作美国信息交换标准代码(American Standard Code for Information Interchange)。
后面计算机传到了全球,人们才发现好像以前的ASCII编码不够用了,好比中文中经常使用的汉字就有4千多个,怎么办呢?
不要紧,将ASCII编码本地化,叫作ANSI编码。1个字节不够用就用2个字节嘛,路是人走出来的,编码也是为人来服务的。因而产生了各类如GB2312, BIG5, JIS等各自的编码标准。这些编码虽然与ASCII编码可是相互之间缺并不兼容。
这严重的影响了国际化的进程,这样还怎么去实现同一个地球,同一片家园的梦想?
因而国际组织出手了,制定了UNICODE字符集,为全部语言的全部字符都定义了一个惟一的编码,unicode的字符集是从U+0000到U+10FFFF这么多个编码。
小师妹:F师兄,那么unicode和我平时据说的UTF-8,UTF-16,UTF-32有什么关系呢?
我笑着问小师妹:小师妹,把大象装进冰箱有几步?
小师妹:F师兄,脑筋急转弯的故事,已经不适合我了,大象装进冰箱有三步,第一打开冰箱,第二把大象装进去,第三关上冰箱,完事了。
小师妹呀,做为一个有文化的中国人,要真正的承担起民族复兴,科技进步的大任,你的想法是很错误的,不能光想口号,要有实际的可操做性的方案才行,要否则咱们何时才可以打造秦芯,唐芯和明芯呢?
师兄说的对,但是这跟unicode有什么关系呢?
unicode字符集最后是要存储到文件或者内存里面的,那怎么存呢?使用固定的1个字节,2个字节仍是用边长的字节呢?根据编码方式的不一样,能够分为UTF-8,UTF-16,UTF-32等多种编码方式。
其中UTF-8是一种变长的编码方案,它使用1-6个字节来存储。UTF-16使用2个或者4个字节来存储,JDK9以后的String的底层编码方式变成了两种:LATIN1和UTF16。
而UTF-32是使用4个字节来存储。这三种编码方式中,只有UTF-8是兼容ASCII的,这也是为何国际上UTF-8编码方式比较通用的缘由(毕竟计算机技术都是西方人搞出来的)。
小师妹,要解决你Properties中的乱码问题很简单,Reader基本上都有一个Charsets的参数,经过这个参数能够传入要读取的编码方式,咱们把UTF-8传进去就好了:
public void usePropertiesWithUTF8() throws IOException{ Properties configProp = new Properties(); InputStream in = this.getClass().getClassLoader().getResourceAsStream("www.flydean.com.properties"); InputStreamReader inputStreamReader= new InputStreamReader(in, StandardCharsets.UTF_8); configProp.load(inputStreamReader); log.info(configProp.getProperty("name")); configProp.setProperty("name", "www.flydean.com"); log.info(configProp.getProperty("name")); }
上面的代码中,咱们使用InputStreamReader封装了InputStream,最终解决了中文乱码的问题。
小师妹又有问题了:F师兄,这样作是由于咱们知道文件的编码方式是UTF-8,若是不知道该怎么办呢?是选UTF-8,UTF-16仍是UTF-32呢?
小师妹问的问题愈来愈刁钻了,还好这个问题我也有准备。
接下来介绍咱们的终极解决办法,咱们将各类编码的字符最后都转换成unicode字符集存到properties文件中,再读取的时候是否是就没有编码的问题了?
转换须要用到JDK自带的工具:
native2ascii -encoding utf-8 file/src/main/resources/www.flydean.com.properties.utf8 file/src/main/resources/www.flydean.com.properties.cn
上面的命令将utf-8的编码转成了unicode。
转换前:
site=www.flydean.com name=程序那些事
转换后:
site=www.flydean.com name=\u7a0b\u5e8f\u90a3\u4e9b\u4e8b
再运行下测试代码:
public void usePropertiesFileWithTransfer() throws IOException { Properties configProp = new Properties(); InputStream in = this.getClass().getClassLoader().getResourceAsStream("www.flydean.com.properties.cn"); configProp.load(in); log.info(configProp.getProperty("name")); configProp.setProperty("name", "www.flydean.com"); log.info(configProp.getProperty("name")); }
输出正确的结果。
若是要作国际化支持,也是这样作的。
千辛万苦终于解决了小师妹的问题,F师兄要休息一下。
本文的例子https://github.com/ddean2009/learn-java-io-nio
本文做者:flydean程序那些事本文连接:http://www.flydean.com/io-charsets-properties/
本文来源:flydean的博客
欢迎关注个人公众号:程序那些事,更多精彩等着您!