java编码解码文件_理清Java中的编码解码转换

1、字符集及编码方式

可以通过Charset.availableCharsets()获取Java支持的字符集,以JDK8为例,得到其支持的字符集:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 SortedMap charsets =Charset.availableCharsets();2 System.out.println(charsets.size());3 for(String key : charsets.keySet()) {4 System.out.println(key + ": " +charsets.get(key));5 }6

7

8 //结果

9 169

10 Big5: Big511 Big5-HKSCS: Big5-HKSCS12 CESU-8: CESU-8

13 EUC-JP: EUC-JP14 EUC-KR: EUC-KR15 GB18030: GB1803016 GB2312: GB231217 GBK: GBK18 IBM-Thai: IBM-Thai19 IBM00858: IBM0085820 IBM01140: IBM0114021 IBM01141: IBM0114122 IBM01142: IBM0114223 IBM01143: IBM0114324 IBM01144: IBM0114425 IBM01145: IBM0114526 IBM01146: IBM0114627 IBM01147: IBM0114728 IBM01148: IBM0114829 IBM01149: IBM0114930 IBM037: IBM03731 IBM1026: IBM102632 IBM1047: IBM104733 IBM273: IBM27334 IBM277: IBM27735 IBM278: IBM27836 IBM280: IBM28037 IBM284: IBM28438 IBM285: IBM28539 IBM290: IBM29040 IBM297: IBM29741 IBM420: IBM42042 IBM424: IBM42443 IBM437: IBM43744 IBM500: IBM50045 IBM775: IBM77546 IBM850: IBM85047 IBM852: IBM85248 IBM855: IBM85549 IBM857: IBM85750 IBM860: IBM86051 IBM861: IBM86152 IBM862: IBM86253 IBM863: IBM86354 IBM864: IBM86455 IBM865: IBM86556 IBM866: IBM86657 IBM868: IBM86858 IBM869: IBM86959 IBM870: IBM87060 IBM871: IBM87161 IBM918: IBM91862 ISO-2022-CN: ISO-2022-CN63 ISO-2022-JP: ISO-2022-JP64 ISO-2022-JP-2: ISO-2022-JP-2

65 ISO-2022-KR: ISO-2022-KR66 ISO-8859-1: ISO-8859-1

67 ISO-8859-13: ISO-8859-13

68 ISO-8859-15: ISO-8859-15

69 ISO-8859-2: ISO-8859-2

70 ISO-8859-3: ISO-8859-3

71 ISO-8859-4: ISO-8859-4

72 ISO-8859-5: ISO-8859-5

73 ISO-8859-6: ISO-8859-6

74 ISO-8859-7: ISO-8859-7

75 ISO-8859-8: ISO-8859-8

76 ISO-8859-9: ISO-8859-9

77 JIS_X0201: JIS_X020178 JIS_X0212-1990: JIS_X0212-1990

79 KOI8-R: KOI8-R80 KOI8-U: KOI8-U81 Shift_JIS: Shift_JIS82 TIS-620: TIS-620

83 US-ASCII: US-ASCII84 UTF-16: UTF-16

85 UTF-16BE: UTF-16BE86 UTF-16LE: UTF-16LE87 UTF-32: UTF-32

88 UTF-32BE: UTF-32BE89 UTF-32LE: UTF-32LE90 UTF-8: UTF-8

91 windows-1250: windows-1250

92 windows-1251: windows-1251

93 windows-1252: windows-1252

94 windows-1253: windows-1253

95 windows-1254: windows-1254

96 windows-1255: windows-1255

97 windows-1256: windows-1256

98 windows-1257: windows-1257

99 windows-1258: windows-1258

100 windows-31j: windows-31j101 x-Big5-HKSCS-2001: x-Big5-HKSCS-2001

102 x-Big5-Solaris: x-Big5-Solaris103 x-euc-jp-linux: x-euc-jp-linux104 x-EUC-TW: x-EUC-TW105 x-eucJP-Open: x-eucJP-Open106 x-IBM1006: x-IBM1006107 x-IBM1025: x-IBM1025108 x-IBM1046: x-IBM1046109 x-IBM1097: x-IBM1097110 x-IBM1098: x-IBM1098111 x-IBM1112: x-IBM1112112 x-IBM1122: x-IBM1122113 x-IBM1123: x-IBM1123114 x-IBM1124: x-IBM1124115 x-IBM1364: x-IBM1364116 x-IBM1381: x-IBM1381117 x-IBM1383: x-IBM1383118 x-IBM300: x-IBM300119 x-IBM33722: x-IBM33722120 x-IBM737: x-IBM737121 x-IBM833: x-IBM833122 x-IBM834: x-IBM834123 x-IBM856: x-IBM856124 x-IBM874: x-IBM874125 x-IBM875: x-IBM875126 x-IBM921: x-IBM921127 x-IBM922: x-IBM922128 x-IBM930: x-IBM930129 x-IBM933: x-IBM933130 x-IBM935: x-IBM935131 x-IBM937: x-IBM937132 x-IBM939: x-IBM939133 x-IBM942: x-IBM942134 x-IBM942C: x-IBM942C135 x-IBM943: x-IBM943136 x-IBM943C: x-IBM943C137 x-IBM948: x-IBM948138 x-IBM949: x-IBM949139 x-IBM949C: x-IBM949C140 x-IBM950: x-IBM950141 x-IBM964: x-IBM964142 x-IBM970: x-IBM970143 x-ISCII91: x-ISCII91144 x-ISO-2022-CN-CNS: x-ISO-2022-CN-CNS145 x-ISO-2022-CN-GB: x-ISO-2022-CN-GB146 x-iso-8859-11: x-iso-8859-11

147 x-JIS0208: x-JIS0208148 x-JISAutoDetect: x-JISAutoDetect149 x-Johab: x-Johab150 x-MacArabic: x-MacArabic151 x-MacCentralEurope: x-MacCentralEurope152 x-MacCroatian: x-MacCroatian153 x-MacCyrillic: x-MacCyrillic154 x-MacDingbat: x-MacDingbat155 x-MacGreek: x-MacGreek156 x-MacHebrew: x-MacHebrew157 x-MacIceland: x-MacIceland158 x-MacRoman: x-MacRoman159 x-MacRomania: x-MacRomania160 x-MacSymbol: x-MacSymbol161 x-MacThai: x-MacThai162 x-MacTurkish: x-MacTurkish163 x-MacUkraine: x-MacUkraine164 x-MS932_0213: x-MS932_0213165 x-MS950-HKSCS: x-MS950-HKSCS166 x-MS950-HKSCS-XP: x-MS950-HKSCS-XP167 x-mswin-936: x-mswin-936

168 x-PCK: x-PCK169 x-SJIS_0213: x-SJIS_0213170 x-UTF-16LE-BOM: x-UTF-16LE-BOM171 X-UTF-32BE-BOM: X-UTF-32BE-BOM172 X-UTF-32LE-BOM: X-UTF-32LE-BOM173 x-windows-50220: x-windows-50220

174 x-windows-50221: x-windows-50221

175 x-windows-874: x-windows-874

176 x-windows-949: x-windows-949

177 x-windows-950: x-windows-950

178 x-windows-iso2022jp: x-windows-iso2022jp

View Code

2、Java中的几种编码格式

2.1、文件、项目、工作空间的编码格式

默认是【文件编码格式】继承于【项目编码格式】继承于【工作空间编码格式】继承于【系统编码格式】。都可以自己设置。

以eclipse里为例:

【工作空间编码格式】设置:在Winodws->Preferences->General->Workspace里设置Text file encoding,默认继承于【系统编码格式】如简体中文环境下是GBK。这样每次新建工程默认都会以此编码

【项目编码格式】设置:在项目右键->Source里设置Text file encoding,默认继承于【工作空间编码格式】。这样在项目下新建文件如java源文件会以此编码。

【文件编码格式】设置:在文件右键->Source里设置Text file encoding,默认继承于【项目编码格式】。

值得注意的是,若在eclipse里保存了.java文件后又用上述方式修改了该文件的编码方式,则可能会出现乱码,并且新输入的代码可能也保存不了,提示输入的有些字符无法用当前编码方式映射保存。乱码原因是用新指定的编码格式来解码原来格式编码成的文件,保存不了原因是新输入的有些字符如中文无法用新编码格式如ISO8859-1编码。所以要修改已写好的.java文件的编码方式,为避免乱码等问题可以在文本编辑器中打开并另存为其他格式。

2.2、运行环境的编码格式

和外部进行数据交换(如读文件时)的时候所用的编码格式。可以通过 Charset.defaultCharset().name() 查看默认编码格式,继承于【文件编码格式】。

Charset.defaultCharset()方法如下:可见Charset.defaultCharset()优先采用 [调用此方法(直接或间接调用)的main函数所在的文件的] file.encoding,无法确认的话用UTF-8,

1 public staticCharset defaultCharset() {2 if (defaultCharset == null) {3 synchronized (Charset.class) {4 String csn =AccessController.doPrivileged(5 new GetPropertyAction("file.encoding"));6 Charset cs =lookup(csn);7 if (cs != null)8 defaultCharset =cs;9 else

10 defaultCharset = forName("UTF-8");11 }12 }13 returndefaultCharset;14 }

需要注意的是,上面的file.encoding指的是main函数所在文件的编码方式,而不是Charset.defaultCharset()代码所在文件的编码方式。如有file1.java、file2.java两个文件,其编码方式不同,file1.java有个静态方法getFileEncoding()返回Charset.defaultCharset(),则file2.java里调用file1.getFileEncoding()得到的是file2.java的编码方式。

另,可在程序里获取file.encoding等system properties:

Properties prop =System.getProperties();

Iterator it=prop.keySet().iterator();while(it.hasNext()) {

String key=it.next().toString();

System.out.println(key+ ": " +prop.getProperty(key));

}

结果中有几个值得注意的属性:

file.encoding: UTF-16 //即前面提到的file.encoding

sun.jnu.encoding: GBK //网上说与文件命名、命令行参数等有关

sun.io.unicode.encoding: UnicodeLittle //应该是Java内部编码,UTF-16L

sun.cpu.endian: little //CPU为小端

这里的file.encoding指的是main函数所在文件的编码方式。

2.3、内部的编码格式

Unicode-16编码,是Java程序内部所用的编码格式。所有外部字符内容在Java 程序内全部转换成此编码格式。

.java文件中的字符串等(3.1)、外部文件、网络资源、数据库资源等读入后转为内部编码格式的数据;写出时从内部编码格式转为指定格式的数据;字符串在内存中也可按指定编码格式进行转换(3.2)。详见章节3。

3、Java中的数据编解码转换

.class文件:UTF-8格式

JVM内部:UTF-16格式

解码:

读:从外部读入(转换为Java内部编码UTF-16):read;用于显示:文本编辑器打开显示

解码成字符(串):new string(byte[])

编码:

写:用于保存或输出到外部(与字符流相关的才需编码,将字符按编码方式转成字节流后输出;若是字节流则直接输出,无需编码)或与外界(网络、数据库等)交互:与字符相关的write,如InputStreamReader、OutputStreamWriter、BufferedWriter等

转变成字节:String.getBytes()

字符(串)与byte[]之间转换时需要提供编码格式参数(然而很多时候我们没提供,其实此时采用了默认格式,即file.encoding)

String值始终是以内部编码格式(UTF-16)存储

3.1、默认转换:Java源文件到.class文件到内存

即编译器根据.java文件的编码格式读出其中的内容并编译成UTF-8格式的.class文件,包括字符串等;运行时JVM按UTF-8格式读取.class文件到内存中。

保存:保存.java文件时,以file.encoding将文件内容编码成二进制存入文件。

编译:运行javac时若没有用-encoding参数指定源文件的编码方式,则以默认格式Charset.defaultCharset()即file.encoding来解码.java文件并编译成UTF-8格式.class文件。

运行:运行Java程序时JVM以UTF-8格式解码.class文件并读入到内存中,此时包括字符串等都以UTF-16格式存在于内存中了。

上述过程一般不需用户干预,除非用户指定其他参数否则可以看出其就是用file.encoding格式来读.java文件并转成内部UTF-16格式的数据,因此这些默认转换一般不会出错。

3.2、运行中转换:网络文件、本地文件、数据库中的内容等

3.2.1、读入

从本地文件中读到内存:按字节读流的话结果(byte[])与程序运行环境的编码格式方式无关,只与文件的编码方式有关;按字符(串)读则与运行环境采用什么编码格式有关,需要将之指定为本地文件的编码方式或父集。这样在读时会以指定编码格式来解码被读取的文件,转变成内部的UTF-16格式于内存中。

从网络文件中读到内存:与上类似。对于与浏览器交互的程序,如Servlet、JSP(也是转换成Servlet放在Web容器临时目录)等,若没有指定编码方式,则默认以ISO8859-1解码接收到的参数、编码返回的数据给浏览器。过程图如下:

e6249f37939b4e5069b5e5f181ce731c.png

从数据库中读取到内存:与上类似,只不过默认编码格式也为8859-1。对于几乎所有数据库的JDBC驱动程序,默认的在JAVA程序和数据库之间传递数据都是以ISO-8859-1为默认编码格式的,所以,我们的程序在向数据库内存储包含中文的数据时,JDBC首先是把程序内部的UNICODE编码格式的数据转化为ISO-8859-1的格式,然后传递到数据库中,在数据库保存数据时,它默认即以ISO-8859-1保存。所以,这是为什么我们常常在数据库中读出的中文数据是乱码。 过程图如下:

8b4add72384ef7d634600e47b2ee34bd.png

3.2.2、写出

从内存中写入到文件:将内存中UTF-16格式的内容 编码成 程序运行环境的编格式的内容,写出到文件。

内存中转换:

内存中数据编码格式转换:转换时一般都要指定某种编码格式,未指定的话采用Charset.defaultCharset()即file.encoding

String转byte[]如getBytes():Java内部编码格式(UTF-16)的数据转换成指定格式的数据

byte[]转String:以指定格式将byte[]数据解码成字符串

其他

3.2.3、console交互:(包含上述的读和写过程)

这种情况,运行该类首先需要JVM支持,即操作系统中必须安装有JRE。运行过程是这样的:首先java启动JVM,此时JVM读出操作系统中保存的class文件并把内容读入内存中,此时内存中为UNICODE格式的class类,然后JVM运行它,如果此时此类需要接收用户输入,则类会默认用file.encoding编码格式对用户输入的串进行编码并转化为unicode保存入内存(用户可以设置输入流的编码格式)。程序运行后,产生的字符串(UNICODE编码的)再回交给JVM,最后JRE把此字符串再转化为file.encoding格式(用户可以设置输出流的编码格式)传递给操作系统显示接口并输出到界面上。 过程图如下:

1fc79212eafc87f866e25f8738424bd7.png

以 下面代码为例,涉及到多次编解码转换(假定文件以UTF-8编码即file.encoding为UTF-8):

FileWriter fw = new FileWriter("文件1.txt");

fw.write(new String("abc".getBytes("GBK"),"UTF-16"));

fw.close();

默认转换

编码:保存.java源文件时,"abc"在文件中以file.encoding的格式编码成二进制存着。

解码编码:编译时,编译器以file.encoding格式解码.java文件并编译成Java内部编码格式即UTF-16格式的.class文件。

解码:程序运行时,JVM加载.class文件,以内部编码格式UTF-16解码.class文件,故"abc"以此格式存在内存中。

程序中转换

编码:"abc".getBytes("GBK")将内存中UTF-16格式的"abc"编码成GBK格式,得到字节数组。

解码:new String(bytes,"UTF-16"))将上步的GBK格式的字节数组解码成UTF-16的字符串。

编码:fw.write()以FileWriter的默认编码方式Charset.defaultCharset()将上步的String编码成二进制写到文件里,当然也可以指定所用的编码方式。所以要正确显示文件里的内容,需要以写入时的相应编码方式来解码打开。

另附一张不是很贴切的图,关于String、char[]、byte[]之间的转换:

ae40e87608a6f38e9c271f86fc8844db.png

4、参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值