`

Java中的字符集编码入门——Java代码中的字符编码转换

阅读更多

 

本文转自 http://www.blogjava.net/zhenandaci/archive/2008/12/25/248213.html

 

如果你是JVM的设计者,让你来决定JVM中所有字符的表示形式,你会不会允许使用各种编码方式的字符并存?
我想你的答案是不会,如果在内存中的Java字符可以以GB2312,UTF-16,BIG5等各种编码形式存在,那么对开发者来说,连进行最基本的字符串打印、连接等操作都会寸步难行。例如一个GB2312的字符串后面连接一个UTF-8的字符串,那么连接后的最终结果应该是什么编码的呢?你选哪一个都没有道理。
因此牢记下面这句话,这也是Java开发者的共同意志:在Java中,字符只以一种编码形式存在,那就是UTF-16。
但“在Java中”到底是指在哪里呢?就是指在JVM中,在内存中,在你的代码里声明的每一个char,String类型的变量中。例如你在程序中这样写

char han='';


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

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


输出是:
6c49
反过来用UTF-16编码来指定一个字符也可以,像这样:

char han=0x6c49;
System.out.println(han);


输出是:

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

JVM的这种约定使得一个字符存在的世界分为了两部分:JVM内部和OS的文件系统。在JVM内部,统一使用UTF-16表示,当这个字符被从JVM内部移到外部(即保存为文件系统中的一个文件的内容时),就进行了编码转换,使用了具体的编码方案(也有一种很特殊的情况,使得在JVM内部也需要转换,不过这个是后话)。
因此可以说,所有的编码转换就只发生在边界的地方,JVM和OS的交界处,也就是你的各种输入输出流(或者Reader,Writer类)起作用的地方。
话头扯到这里就必须接着说Java的IO系统。
尽管看上去混乱繁杂,但是所有的IO基本上可以分为两大阵营:面向字符的Reader啊Wrtier啊,以及面向字节的输入输出流。
下面我来逐一分解,其实一点也不难。
面向字符和面向字节中的所谓“面向”什么,是指这些类在处理输入输出的时候,在哪个意义上保持一致。如果面向字节,那么这类工作要保证系统中的文件二进制内容和读入JVM内部的二进制内容要一致。不能变换任何0和1的顺序。因此这是一种非常“忠实于原著”的做法(偶然间让我想起郭敬明抄袭庄羽的文章,那家伙,太忠实于原著了,笑)。
这种输入输出方式很适合读入视频文件或者音频文件,或者任何不需要做变换的文件内容。
而面向字符的IO是指希望系统中的文件的字符和读入内存的“字符”(注意和字节的区别)要一致。例如我们的中文版WindowsXP系统上有一个GBK的文本文件,其中有一个“汉”字,这个字的GBK编码是0xBABA(而UTF-16编码是0x6C49),当我们使用面向字符的IO把它读入内存并保存在一个char型变量中时,我希望IO系统不要傻傻的直接把0xBABA放到这个char型变量中,我甚至都不关心这个char型变量具体的二进制内容到底是多少,我只希望这个字符读进来之后仍然是“汉”这个字。
从这个意义上也可以看出,面向字符的IO类,也就是Reader和Writer类,实际上隐式的为我们做了编码转换,在输出时,将内存中的UTF-16编码字符使用系统默认的编码方式进行了编码,而在输入时,将文件系统中已经编码过的字符使用默认编码方案进行了还原。我两次提到“默认”,是说Reader和Writer的聪明也仅此而已了,它们只会使用这个默认的编码来做转换,你不能为一个Reader或者Writer指定转换时使用的编码。这也意味着,如果你使用中文版WindowsXP系统,而上面存放了一个UTF-8编码的文件,当你使用Reader类来读入的时候,它会傻傻的使用GBK来做转换,转换后的内容当然驴唇不对马嘴!
这种笨,有时候其实是一种傻瓜式的功能提供方式,对大多数初级用户(以及不需要跨平台的高级用户)来说反而是件好事。
但我们不一样啦,我们都是国家栋梁,肩负着赶英超美的责任,必须师夷长技以治夷,所以我们总还要和GBK编码以外的文件打交道。
说了上面这些内容,想必聪明的读者已经看出来,所谓编码转换就是一个字符与字节之间的转换,因此Java的IO系统中能够指定转换编码的地方,也就在字符与字节转换的地方,那就是(读者:InputSteamReader和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!(这正是“汉”这个字的UTF-8编码)噢耶!(读者:这,这有什么好高兴的……)
下一节我们来看看实现这种操作的其他方式,读到这里,你已经基本上是字符编码的高手了哦。

分享到:
评论

相关推荐

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

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

    编码——隐匿在计算机背后的软硬件语言

    5. **指令集与CPU**:CPU通过执行指令来完成任务,书中会讲解指令集架构(ISA)的概念,以及如何通过汇编语言与机器语言进行编程。 6. **编译器与解释器**:这两种工具将高级语言转换为机器可执行的代码。编译器一...

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

    3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63 3.5 习题 65 第4章 Java中的程序执行流程 67 教学视频:1小时57分钟 4.1 顺序执行 67 4.2 使用if-else让程序懂得判断 68 4.2.1 if语句 68 4.2.2 ...

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

    3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63 3.5 习题 65 第4章 Java中的程序执行流程 67 教学视频:1小时57分钟 4.1 顺序执行 67 4.2 使用if-else让程序懂得判断 68 4.2.1 if语句 68 4.2.2 ...

    JAVA上百实例源码以及开源项目源代码

    Java局域网通信——飞鸽传书源代码 28个目标文件 内容索引:JAVA源码,媒体网络,飞鸽传书 Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java...

    JavaWeb开发教程——入门与提高篇(含PDF课件和源码)

    Filter用于在请求处理前后执行特定逻辑,如字符编码转换、安全检查等。Listener则监听Web应用中的事件,如会话创建、销毁等,可实现更精细的控制。 7. **Struts、Spring MVC或JSF框架** 这些框架提供了更高层次的...

    Java开发详解.zip

    031216_【第12章:JAVA IO】_字符编码笔记.pdf 031217_【第12章:JAVA IO】_对象序列化笔记.pdf 031218_〖第12章:JAVA IO〗_实例操作—单人信息管理程序笔记.pdf 031219_〖第12章:JAVA IO〗_实例操作:投票程序...

    (jsp入门)图书管理系统---支持中文不乱码

    系统需确保从客户端到服务器再到数据库的整个过程中,字符编码保持一致。在JSP中,我们可以使用`;charset=UTF-8"%>`指令设置页面编码为UTF-8。同时,确保数据库连接配置也使用UTF-8编码,例如在MySQL中,可以设置...

    Visual C++ 2005入门经典--源代码及课后练习答案

    Ivor Horton还著有Beginning Visual C++ 6、Beginning C Programming和Beginning Java 2等多部入门级好书。 目录 封面 -18 前言 -14 目录 -9 第1章 使用Visual C++ 2005编程 1 1.1 .NET Framework 1 1.2 CLR 2...

    Java软件开发实战 Java基础与案例开发详解 4-5 增强for循环 共5页.pdf

    - **转换流**:用于转换字符集。 - **数据流与打印流**:处理基本数据类型的流和打印格式化的文本。 - **对象流**:用于序列化和反序列化对象。 - **随机存取文件流**:支持随机访问文件内容的流。 - **ZIP文件流**...

    JSP语法.rar

    - `<%@ page %>`: 用于设置JSP页面的属性,如语言、字符集、错误页等。 - `<%@ include %>`: 用于在页面编译时将另一个文件包含进来。 - `<%@ taglib %>`: 引入自定义标签库。 3. **脚本元素(Scriptlets)**:...

    mybatis_01 入门配置 Dao的两种开发方法

    - **结果集处理重复**: 对于结果集的处理往往需要写大量的重复代码,尤其是在将结果转换为 Java 对象时。 ##### MyBatis 解决方案 - **MyBatis** 是 Apache 软件基金会下的一个开源项目,前身是 iBatis 框架。2010 ...

    FreeMarker手册(用于2.3.19)

    配置是指设置FreeMarker的一些基本选项,如模板的加载路径、字符集编码等。 **3.2 共享变量** 共享变量是在多个模板之间共享的数据。 **3.3 配置信息** 配置信息包括模板的加载方式、错误处理机制等。 **3.4 ...

    FreeMarker实例教程,手把手教你FreeMarker的方方面面

    - **字符集问题**:讨论了如何处理多字符集环境下的文本编码问题。 - **多线程**:介绍了FreeMarker在多线程环境下的使用技巧。 - **Bean的包装**:讲解了如何将Java Bean转换为FreeMarker可以访问的格式。 - **日志...

    Mastering Apache Spark

    - **编码器 (Encoders)**:为了在 Java 或 Scala 中使用 Dataset,需要提供编码器,这些编码器负责在内部 Row 与实际数据类型之间进行转换。 - **内部 Row (InternalRow)**:这是 Spark SQL 内部使用的二进制格式,...

    oracle ebs开发文档

    这部分讲解了如何在 PL/SQL 中调用 Java 代码,这对于需要集成外部服务或使用 Java 库的情况非常有用。 **5.3 PL/SQL 操作 EXCEL** 这部分介绍了如何使用 PL/SQL 来读写 Excel 文件,这对于数据导出或导入的需求...

    PLSQLDeveloper下载

    该特性提高了您编码的生产力,改善了PL/SQL代码的可读性,促进了大规模工作团队的协作。 SQL 窗口——该窗口允许您输入任何SQL语句,并以栅格形式对结果进行观察和编辑,支持按范例查询模式,以便在某个结果集合中...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    简单来说是本身可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据运行新增、截取、更新、删除等操作。 常见的数据模型 1. 层次结构模型: 层次结构模型实质上是一种有根结点的定向有序树,IMS...

    新版Android开发教程.rar

    Android 是一个专门针对移动设备的软件集,它包括一个操作系统,中间件和一些重要的应用程序。 Beta 版 的 Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 ...

Global site tag (gtag.js) - Google Analytics