`

【java】Java编码字符集与字符集编码入门(五) Java代码中的字符编码转换Part1

    博客分类:
  • java
阅读更多

 

  • Java使用的统一字符集Unicode

    如果你是JVM的设计者,让你来决定JVM中所有字符的表示形式,你会不会允许使用各种编码方式的字符并存? 

 

    我想你的答案是不会,如果在内存中的Java字符可以以GB2312,UTF-16,BIG5等各种编码形式存在,那么对开发者来说,连进行最基本的字符串打印、连接等操作都会寸步难行。例如一个GB2312的字符串后面连接一个UTF-8的字符串,那么连接后的最终结果应该是什么编码的呢?你选哪一个都没有道理。

 

    因此牢记下面这句话,这也是Java开发者的共同意志:在Java中,字符只以一种形式存在,那就是Unicode(注意到我们没有选择特定的编码,直接使用它们在字符集中的编号,这是统一的唯一方法)。

 

    但“在Java中”到底是指在哪里呢?就是指在JVM中,在内存中,在你的代码里声明的每一个char,String类型的变量中。例如你在程序中这样写 

    char han='汉'; 

 

    在内存的相应区域,这个字符就表示为0x6C49.可以用下面的代码证明一下: 

    char han='汉';

    System.out.format("%x",(short)han); 

    输出是:6c49

 

    反过来用Unicode编号来指定一个字符也可以,像这样: 

    char han=0x6c49;

    System.out.println(han);

    输出是:汉 

 

    这其实也是说,只要你正确的读入了“汉”这个字,那么它在内存中的表示形式一定是0x6C49,没有任何其他的值能代表这个字(当然,如果你读错了,那结果是什么就不知道了,范伟说:读,读错了呀,那还等于好几亿呢;本山大哥说:好几亿你也没答上,请听下一题)。

 

    JVM的这种约定使得一个字符存在的世界分为了两部分:JVM内部和OS的文件系统。在JVM内部,统一使用Unicode表示,当这个字符被从JVM内部移到外部(即保存为文件系统中的一个文件的内容时),就进行了编码转换,使用了具体的编码方案(也有一种很特殊的情况,使得在JVM内部也需要转换,不过这个是后话)。 

 

    因此可以说,所有的编码转换就只发生在边界的地方,JVM和OS的交界处,也就是你的各种输入输出流(或者Reader,Writer类)起作用的地方。

 

 

 

  • Java的IO系统

    话头扯到这里就必须接着说Java的IO系统。

 

    尽管看上去混乱繁杂,但是所有的IO基本上可以分为两大阵营:面向字符的Reader啊Wrtier啊,以及面向字节的输入输出流。

 

    下面我来逐一分解,其实一点也不难。

 

    面向字符和面向字节中的所谓“面向”什么,是指这些类在处理输入输出的时候,在哪个意义上保持一致。如果是面向字节,那么这类工作要保证系统中的文件二进制内容和读入JVM内部的二进制内容要一致。不能变换任何0和1的顺序(也就是文件是怎么存的就怎么取,与文件保存的编码一致)。因此这是一种非常“忠实于原著”的做法(偶然间让我想起郭敬明抄袭庄羽的文章,那家伙,太忠实于原著了,笑)。

 

    这种输入输出方式很适合读入视频文件或者音频文件,或者任何不需要做变换的文件内容。

 

    而面向字符的IO是指希望系统中的文件的字符和读入内存的“字符”(注意和字节的区别)要一致。例如我们的中文版WindowsXP系统上有一个GBK的文本文件,其中有一个“汉”字,这个字的GBK编码是0xBABA(而Unicode编号是0x6C49),当我们使用面向字符的IO把它读入内存并保存在一个char型变量中时,我希望IO系统不要傻傻的直接把0xBABA放到这个char型变量中,我甚至都不关心这个char型变量具体的二进制内容到底是多少,我只希望这个字符读进来之后仍然是“汉”这个字。 

 

    从这个意义上也可以看出,面向字符的IO类,也就是Reader和Writer类,实际上隐式的为我们做了编码转换,在输出时,将内存中的Unicode字符使用系统默认的编码方式进行了编码,而在输入时,将文件系统中已经编码过的字符使用默认编码方案进行了还原。我两次提到“默认”,是说Reader和Writer的聪明也仅此而已了,它们只会使用这个默认的编码来做转换,你不能为一个Reader或者Writer指定转换时使用的编码。这也意味着,如果你使用中文版WindowsXP系统,而上面存放了一个UTF-8编码的文件,当你使用Reader类来读入的时候,它会傻傻的使用GBK来做转换,转换后的内容当然驴唇不对马嘴! 

 

    这种笨,有时候其实是一种傻瓜式的功能提供方式,对大多数初级用户(以及不需要跨平台的高级用户)来说反而是件好事。 

 

    但我们不一样啦,我们都是国家栋梁,肩负着赶英超美的责任,必须师夷长技以治夷,所以我们总还要和GBK编码以外的文件打交道。

 

 

 

Java中的编码转换(俗称转码)

    说了上面这些内容,想必聪明的读者已经看出来,所谓编码转换就是一个字符与字节之间的转换,因此Java的IO系统中能够指定转换编码的地方,也就在字符与字节转换的地方,那就是(读者:InputStreamReader和OutputStreamWriter!作者:太强了,都会抢答了!)

 

 

    PrintStream也可以对OutputStream进行包装并指定编码方式:PrintStream(OutputStream out,

boolean autoFlush, String encoding),但实质上也是调用OutputStreamWriter来实现的。

 

    这两个类是字节流和字符流之间的适配器类,因此他们肩负着编码转换的任务简直太自然啦!要注意,实际上也只能在这两类实例化的时候指定编码,是不是很好记呢?

 

    下面来写一段小程序,来把“汉”字用我们非常崇拜的UTF-8编码写到文件中! 

try {
	PrintWriter out = new PrintWriter(new OutputStreamWriter(
			new FileOutputStream("c:/utf-8.txt"), "UTF-8"));
	try {
	    out.write("汉");
	} finally {
	    out.close();
	}
} catch (IOException e) {
	throw new RuntimeException(e);

}

 

 

    运行之后到c盘下去找utf-8.txt这个文件,用UltraEdit打开,使用16进制查看,看到了什么?它的值是0xE6B189!噢耶!(读者:这,这有什么好高兴的……) 

分享到:
评论

相关推荐

    Java中的字符集编码入门(五)Java代码中的字符编码转换Part1.pdf

    Java中的字符编码转换是编程实践中一个至关重要的概念,尤其是在处理多语言环境和跨平台交互时。Java通过统一采用UTF-16编码格式在JVM内部处理字符,简化了字符操作的复杂性。UTF-16是一种变长的Unicode编码,它可以...

    Java中的字符集编码入门(五)Java代码中的字符编码转换Part1.doc

    ### Java中的字符集编码入门(五):Java代码中的字符编码转换Part1 #### 核心知识点概述: 本文档深入探讨了Java编程语言中字符集编码的基础知识,并着重讲解了字符编码转换的基本原理及其在Java代码中的应用。...

    Java中的字符集编码入门(五)Java代码中的字符编码转换Part1[参考].pdf

    Java中的字符编码转换是编程实践中不可或缺的一部分,尤其是在处理多语言和跨平台的场景下。Java选择了UTF-16作为其内部字符表示的标准,这确保了在JVM内存中,所有字符都以统一的方式存储,避免了编码不一致带来的...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    一一击破Java入门可能会遇到的难点和疑惑 抽丝剥茧,层层推进,让知识环环相扣,降低了学习的难度 通过大量的比喻、类比、对比和图示等多种讲解方式,学习效果好 对Java语言的每个语法都提供了一个或多个例程讲解 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    一一击破Java入门可能会遇到的难点和疑惑 抽丝剥茧,层层推进,让知识环环相扣,降低了学习的难度 通过大量的比喻、类比、对比和图示等多种讲解方式,学习效果好 对Java语言的每个语法都提供了一个或多个例程讲解 ...

    java项目中公共模块内容详细

    1. **编码**:在Java中,编码问题主要涉及字符集如UTF-8、GBK等。开发者通常会处理字符编码的转换,以确保数据在不同系统和环境中的一致性。例如,`String`到`byte[]`或反之的转换,以及在输入输出流中设置正确的...

    Java正则表达式入门及用法

    - `[]`:表示字符集,可以指定一个范围或者多个字符中的任意一个。 - `[a-z]`:匹配任何小写字母。 - `[A-Z]`:匹配任何大写字母。 - `[a-zA-Z]`:匹配任何字母。 - `[0-9]`:匹配任何数字。 - `[0-9a-z]`:...

    Java Web编程宝典-十年典藏版.pdf.part2(共2个)

    共24章,其中,第1篇为技能学习篇,主要包括Java Web开发环境、JSP语法、JSP内置对象、Java Bean技术、Servlet技术、EL与JSTL标签库、数据库应用开发、初识Struts2基础、揭密Struts2高级技术、Hib锄劬e技术入门、...

    jquery fileupload上传百分比 JAVA版解决中文乱码

    1. **设置HTTP请求编码**:在发送文件上传请求时,需要在Content-Type头中明确指定字符集为UTF-8,例如`Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW;charset=UTF-8`。 2. ...

    Java程序设计课件:5 数组与字符串_part1.ppt

    Java中的数组和字符串是编程中基础且重要的概念,它们在数据处理和算法实现中起着核心作用。数组是一种数据结构,允许我们存储多个相同类型的值在一个单一的变量中。数组通常由固定大小的元素序列组成,这些元素在...

    JavaSE基础入门视频教程33天之(23) part3

    本教程“JavaSE基础入门视频教程33天之(23) part3”专注于IO流,这是Java中处理输入输出数据的重要概念。IO流允许程序与外部设备,如磁盘、网络或内存进行数据交换。 IO流在Java中分为两大类:字节流(Byte ...

    HTML特殊字符编码大全

    基于名称的实体更易于记忆,而基于数字的实体则更加通用,因为它们并不依赖于字符集。 #### 二、特殊符号与标点符号 特殊符号和标点符号在网页设计中非常常见,用于增强文本的表现力。下面列举了一些常见的特殊...

    JAVA中文上传

    综上所述,"JAVA中文上传"涉及的主要知识点包括J2EE环境下的文件上传处理,尤其是解决中文文件名的编码问题,以及与之相关的字符集配置、安全性和性能优化措施。通过合理地运用相关技术和库,我们可以确保在Java应用...

    java读取远程网页乱码解决方案

    网页通常使用UTF-8、GBK等字符集编码,Java在读取时必须识别并匹配这种编码,才能正确解析字符。当Java程序以错误的编码读取网页时,会出现乱码现象。 一、使用`java.net.URL`和`BufferedReader` 1. 创建`URL`对象...

    Docker容器中文乱码(修改docker容器编码格式)的解决方案

     问题经过定位,发现后台代码的multipartfile类在执行transterto的方法时就发生了此异常,然而配置文件集中的multipartResolver以及encodingFilter均已经设置成了UTF-8,排除代码异常。kubectl exec进入到docker...

    Introduction to Java Programming(10th Edition)课后练习答案

    1. **基础语法**:Java的基础语法包括变量声明、数据类型(如整型、浮点型、字符型、布尔型)、运算符(算术、比较、逻辑、位操作等)、流程控制语句(如if-else、switch、for、while循环)以及方法定义。...

    Java2核心技术.part5

    1. 3 Java与Internet 1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 ...

    Java2核心技术.part1

    1. 3 Java与Internet 1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5...

Global site tag (gtag.js) - Google Analytics