`
javasogo
  • 浏览: 1774654 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

JAVA 字符串编码总结

阅读更多

String newStr = new String(oldStr.getBytes(), "UTF-8");

java中的String类是按照unicode进行编码的,当使用String(byte[] bytes, String encoding)构造字符串时,encoding所指的是bytes中的数据是按照那种方式编码的,而不是最后产生的String是什么编码方式,换句话说,是让系统把bytes中的数据由encoding编码方式转换成unicode编码。如果不指明,bytes的编码方式将由jdk根据操作系统决定。

当我们从文件中读数据时,最好使用InputStream方式,然后采用String(byte[] bytes, String encoding)指明文件的编码方式。不要使用Reader方式,因为Reader方式会自动根据jdk指明的编码方式把文件内容转换成unicode 编码。

当我们从数据库中读文本数据时,采用ResultSet.getBytes()方法取得字节数组,同样采用带编码方式的字符串构造方法即可。

ResultSet rs;
bytep[] bytes = rs.getBytes();
String str = new String(bytes, "gb2312");

不要采取下面的步骤。

ResultSet rs;
String str = rs.getString();
str = new String(str.getBytes("iso8859-1"), "gb2312");

这种编码转换方式效率底。之所以这么做的原因是,ResultSet在getString()方法执行时,默认数据库里的数据编码方式为 iso8859-1。系统会把数据依照iso8859-1的编码方式转换成unicode。使用str.getBytes("iso8859-1")把数据还原,然后利用new String(bytes, "gb2312")把数据从gb2312转换成unicode,中间多了好多步骤。

从HttpRequest中读参数时,利用reqeust.setCharacterEncoding()方法设置编码方式,读出的内容就是正确的了。


先说Java。
JVM里面的任何字符串资源都是Unicode,就是说,任何String类型的数据都是Unicode编码。没有例外。既然只有一种编码,那么,我们可以这么说,JVM里面的String是不带编码的。String相当于 char[]。
JVM里面的 byte[] 数据是带编码的。比如,Big5,GBK,GB2312,UTF-8之类的。
一个GBK编码的byte[] 转换成 String,其实就是从GBK编码向Unicode编码转换。
一个String转换成一个Big5编码的byte[],其实就是从Unicode编码向Big5编码转换。
所以,Unicode是所有编码转换的中间介质。所有的编码都有一个转换器可以转换到Unicode,而Unicode也可以转换到其他所有的编码。这样构成了一个总线结构。
比如,如果总共有10种编码,那么只需要 10 + 10 = 20个转换器就够了。如果要是两两直接转换,那么,需要的转换器数量是一个组合数字,需要90个转换器。

一个系统的不同部分,都有自己的编码。比如,数据库,文件,JVM,浏览器这4个部分。
在这些部分之间数据交换的地方,就会出现编码问题。比如,数据库和JVM之间,文件和JVM之间,浏览器和JVM之间。这些问题的原理都是相通的。

编码问题最容易处理的地方是文件和JVM之间。文件IO API带有encoding 参数,请自行查阅。
最不容易出现编码问题的地方是数据库和JVM之间。这应该是数据库JDBC连接的基本功能。本文不专门进行讨论。
最容易出问题的地方是浏览器和服务器JVM之间(其实,代码里面的字符串更容易出问题,不过,我已经事先声明,本文不讨论代码中的字符串编码)。下面主要讨论这块浏览器和服务器JVM之间的编码问题。

我们把浏览器编码叫做 Browser_Charset,把JVM编码叫做JVM_Charset(通常等于服务器系统编码)。
当浏览器的数据过来的时候,是一个带有Browser_Charset的byte[]。
如果用户处理程序需要一个String类型的数据,那么JVM会好心好意地把这个byte[]转换成String。使用的转换器是 JVM_Charset -> Unicode。
注意,如果这个时候,Browser_Charset 和 JVM_Charset并不相等。那么,这个自动转换是错误的。
为了弥补这个错误。我们需要做两步工作。
(1) Unicode -> JVM_Charset,把这个String 转换回到原来的 byte[]。
(2) Browser_Charset -> Unicode,把这个还原的byte[]转换成 String。

这个效果,和直接从HTTP Request取得byte[],然后执行 (2) Browser_Charset -> Unicode 的效果是一样的。

如果在Request里面设置了CharacterEncoding,那么POST Data参数就不需要自己手工转换了,web server的自动转换就是正确的。URL的参数编码还涉及到URL编码,需要考虑的问题多一些,没有这么简单。

JVM把数据发到浏览器的时候。也需要考虑编码问题。可以在Response里面设置。另外,HTML Meta Header里面也可以设置编码,提醒Browser选择正确编码。

有些语言的VM或者解释器的字符串编码可能不同。比如,Ruby。不过,编码转换原理都是一样的。

That is all.

JAVA字符编码

一、概要
在JAVA应用程序特别是基于WEB的程序中,经常遇到字符的编码问题。为了防止出现乱码,首先需要了解JAVA是如何处理字符的,这样就可以有目的地在输入/输出环节中增加必要的转码。其次,由于各种服务器有不同的处理方式,还需要多做试验,确保使用中不出现乱码。
二、基本概念
2.1 JAVA中字符的表达
JAVA 中有char、byte、String这几个概念。char 指的是一个UNICODE字符,为16位的整数。byte 是字节,字符串在网络传输或存储前需要转换为byte数组。在从网络接收或从存储设备读取后需要将byte数组转换成String。String是字符串,可以看成是由char组成的数组。String 和 char 为内存形式,byte是网络传输或存储的序列化形式。
举例:

String ying = “英”;
char ying = ying.charAt(0);
String yingHex = Integer.toHexString(ying);
82 F1
byte yingGBBytes = ying.getBytes(“GBK”);
GB编码的字节数值
D3 A2
2.2 编码方式的简介
String序列化成byte数组或反序列化时需要选择正确的编码方式。如果编码方式不正确,就会得到一些0x3F的值。常用的字符编码方式有ISO8859_1、GB2312、GBK、UTF-8/UTF-16/UTF-32。
ISO8859_1用来编码拉丁文,它由单字节(0-255)组成。
GB2312、GBK用来编码简体中文,它有单字节和双字节混合组成。最高位为1的字节和下一个字节构成一个汉字,最高位为0的字节是ASCII码。
UTF-8/UTF-16/UTF-32是国际标准UNICODE的编码方式。 用得最多的是UTF-8,主要是因为它在对拉丁文编码时节约空间。
UNICODE值 UTF-8编码
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
三、J2SE中相关的函数
String str =”英”;
//取得GB2312编码的字节
byte[] bytesGB2312 = str.getBytes(“GB2312”);
//取得平台缺省编码的字节(solaris为ISO8859_1,windows为GB2312)
byte[] bytesDefault = str.getBytes();
//用指定的编码将字节转换成字符串
String newStrGB = new String(bytesGB2312, “GB2312”);

//用平台缺省的编码将字节转换成字符串(solaris为ISO8859_1,windows为GB2312)
String newStrDefault = new String(bytesDefault);
//用指定的编码从字节流里面读取字符
InputStream in = xxx;
InputStreamReader reader = InputStreamReader( in, “GB2312”);
char aChar = reader.read();
四、JSP、数据库的编码
4.1 JSP中的编码
(1) 静态声明:
CHARSET有两个作用:
JSP文件的编码方式:在读取JSP文件、生成JAVA类时,源JSP文件中汉字的编码
JSP输出流的编码方式:在执行JSP时,往response流里面写入数据的编码方式
(2) 动态改变:在往response流里面写数据前可以调用response.setContentType(),设定正确的编码类型。
(3) 在TOMCAT中,由Request.getParameter() 得到的参数,编码方式都是ISO8859_1。所以如果在浏览器输入框内输入一个汉字“英”,在服务器端就得到一个ISO8859_1编码的(0x00,0xD3,0x00,0xA2)。所以通常在接收参数时转码:
String wrongStr = response.getParameter(“name”);
String correctStr = new String(wrongStr.getBytes(“ISO8859_1”),”GB2312”);
在最新的SERVLET规范里面,也可以在获取参数之前执行如下代码:
request.setCharacterEncoding(“GB2312”);
4.2 数据库的编码
(1) 数据库使用UTF-16
如果String中是UNICODE字符,写入读出时不需要转码
(2) 数据库使用ISO8859_1
如果String中是UNICODE字符,写入读出时需要转码
写入:String newStr = new String(oldStr.getByte(“GB2312”), “ISO8859_1”);
读出:String newStr = new String(oldStr.getByte(“ISO8859_1”),”GB2312”);
五、源文件的编码
5.1 资源文件
资源文件的编码方式和编辑平台相关。在WINDOWS平台下编写的资源文件,以GB2312方式编码。在编译时需要转码,以确保在各个平台上的正确性:
native2ascii ?encoding GB2312 source.properties
这样从资源文件中读出的就是正确的UNICODE字符串。
5.2 源文件
源文件的编码方式和编辑平台相关。在WINDOWS平台下开发的源文件,以GB2312方式编码。在编译的时候,需要指定源文件的编码方式:
javac ?encoding GB2312
JAVA编译后生成的字节文件的编码为UTF-8。

①最新版TOMCAT4.1.18支持request.setCharacterEncoding(String enc)
②资源文件转码成company.name=u82f1u65afu514b
③如果数据库使用utf-16则不需要这部分转码
④页面上应有
转码?:
String s = new String
(request.getParameter(“name”).getBytes(“ISO8859_1”),”GB2312”);
转码?:
String s = new String(name.getBytes(“GB2312”),”ISO8859_1”);
转码?:
String s = new String(name.getBytes(“ISO8859_1”),” GB2312”);



=========================================================

JAVA内部究竟是用的什么字符编码呢?这个问题我也找了很久,后来在THINK IN JAVA 3rd的12章里看到一个例子出现了UTF-16BE,难道是它?
byte[] utf_16be = name.getBytes("utf-16be");

printbyte(utf_16be);

结果出来了:58 02 length = 2
哈哈,I got it!不多不少两个字节,内容也一样。果然是它。同时我在里面也看到,UNICODE的编码还有一个LE,这里的BE,LE我想应该是bigendian和littleendian吧。

==========================================================

import java.io.*;
public class TestCodeIO {
public static void main(String[] args) throws Exception{
InputStreamReader isr = new InputStreamReader(System.in,"iso8859-1");
//Create an InputStreamReader that uses the given charset decoder
BufferedReader br = new BufferedReader (isr);
String strLine = br.readLine();
br.close();
isr.close();
System.out.println(strLine);
System.out.println(new String (strLine.getBytes(),"iso8859-1"));//错误改法
//Encodes this String (strLine) into a sequence of bytes using the platform's
//default charset(gb2312) then constructs a new String by decoding the
//specified array of bytes using the specified charset (iso8859-1)
//because this String (strLine) uses the charset decoder "iso8859-1",so it can
//only be encoded by "iso8859-1",cann't be encoded by the platform's default
//charset "gb2312",so this line is wrong.
System.out.println(new String (strLine.getBytes("iso8859-1")));//正确改法
//Encodes this String (strLine) into a sequence of bytes using the named
//charset (iso8859-1),then constructs a new String by decoding the
//specified array of bytes using the platform's default charset (gb2312).
//This line is right.
}
}

上面的英文注释已经说得很清楚了,这里我还是解释一下吧:

首先是错误的改法 System.out.println(new String (strLine.getBytes(),"iso8859-1"));
这句代码是将strLine中的字符串用系统默认的编码方式(这里是gb2312)
转换为字节序列,然后用指定的编码方式(这里是iso8859-1)构造一个新的
String对象,并打印到屏幕上。
错误在哪里呢?

请注意这一段代码
InputStreamReader isr = new InputStreamReader(System.in,"iso8859-1");
BufferedReader br = new BufferedReader (isr);
String strLine = br.readLine();
这里strLine存储的内容是用指定的编码方式(iso8859-1)存储的,而转换成字节码
的时候(这句代码strLine.getBytes())却使用了系统默认的gb2312编码,所以当然就
输出乱码了!然后用gb2312编码的字节序列构建新的String对象的时候又使用了
iso8859-1编码,所以输出的乱码和System.out.println(strLine)有所不同。

至于正确的改法就不用详细说明了吧,首先将strLine用iso8859-1编码方式转换成字节
序列,然后用系统默认的编码方式(gb2312)构建新的String对象,然后打印输出。

参考:

字符串编码(charset, encoding/decoding)问题原理

http://www.iteye.com/topic/31860

主题:Java编码浅析(注意区分三个概念)

http://www.iteye.com/topic/311583

java 字符编码

http://wenku.baidu.com/view/3668f2d6195f312b3169a571.html

分享到:
评论

相关推荐

    java字符串编码转换代码

    总结了java中常见的utf-8、gbk等进行字符串编码转换

    JAVA字符编码问题总结

     我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节(byte)。  也就是说,一个字节一共...

    125集专攻JAVA基础 JAVA零基础入门学习视频教程 动力节点JAVA视频教程.txt

    北京动力节点-Java编程零基础教程-091-Java基本语法-控制语句-switch语句-字符串作为比较对象.avi 北京动力节点-Java编程零基础教程-092-Java基本语法-控制语句-switch语句-举例1.avi 北京动力节点-Java编程零...

    java 面试题 总结

    JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变...

    计算机程序设计(Java)-教案--单元二--Java语言开发基础.docx.docx

    数据类型、运算符、字符串、数组等知识在编程过程中能熟练、准确应用; ・:・能熟练、准确地应用分支、循环、跳转三种流程执行过程; 教学重点 :・标识符命名规那么、数据类型与运算符; : 嵌套ifelse语句的用法...

    Thinking in java4(中文高清版)-java的'圣经'

    非静态实例初始化 5.8 数组初始化 5.8.1 可变参数列表 5.9 枚举类型 5.10 总结 第6章 访问权限控制 第7章 复用类 第8章 多态 第9章 接口 第10章 内部类 第11章 持有对象 第12章 通过异常处理错误 第13章 字符串 第...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    4.4.3 字符串编码 115 4.5 查询java api文件 117 4.6 重点复习 119 4.7 课后练习 120 chapter5 对象封装 125 5.1 何谓封装 126 5.1.1 封装对象初始流程 126 5.1.2 封装对象操作流程 128 5.1.3 封装...

    Java之IO流学习总结

    字符串文件路径;b.File对象。 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw) 注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定...

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

    9.2.6 在字符串中查找子字符串或字符 226 9.2.7 替换字符串中的内容 226 9.2.8 String对象——磐石刻字 227 9.3 String类的最佳拍档——StringBuffer类 227 9.3.1 StringBuffer:专业操纵字符 228 9.3.2 String...

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

    9.2.6 在字符串中查找子字符串或字符 226 9.2.7 替换字符串中的内容 226 9.2.8 String对象——磐石刻字 227 9.3 String类的最佳拍档——StringBuffer类 227 9.3.1 StringBuffer:专业操纵字符 228 9.3.2 String...

    Java面试宝典2010版

    19、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 90 20.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序...

    [享学Feign] 九、Feign + OkHttp和Feign + Apache HttpClient哪个更香?

    Redis作者说到:“灵活性被过分高估–>约束才是解放”。...其实核心模块可以独立的work,但是不免它的能力偏弱,比如只能编码字符串类型、只能解码字符串类型,默认使用java.net.HttpURLConnection作为HC… 本篇将

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

    4.1.4 字符数组和字符串处理 147 4.1.5 多维数组 150 4.2 间接数据存取 153 4.2.1 指针的概念 153 4.2.2 声明指针 154 4.2.3 使用指针 155 4.2.4 初始化指针 157 4.2.5 sizeof运算符 162 4.2.6 ...

    改之理java源码复制-sg16-meetings:SG16会议计划和总结

    改之理java源码复制SG16 会议 SG16 会议通常在每个月的第 2 周和第 4 周的 UTC 时间周三 ...(包括格式字符串、程序员提供的字段参数和语言环境提供的文本)将以兼容的编码提供与文字编码? 对std::print(

    《算法》中文版,Robert Sedgewick,塞奇威克

     2、内容全面:全面论述排序、搜索、图处理和字符串处理的算法和数据结构,涵盖每位程序员应知应会的50种算法  3、全新修订的代码:全新的Java实现代码,采用模块化的编程风格,所有代码均可供读者使用  4、与...

    算法-第4版-完整版

    1.1.8 字符串 20 1.1.9 输入输出 21 1.1.10 二分查找 28 1.1.11 展望 30 1.2 数据抽象 38 1.2.1 使用抽象数据类型 38 1.2.2 抽象数据类型举例 45 1.2.3 抽象数据类型的实现 52 1.2.4 更多...

    算法 第4版-谢路云译-带完整书签

    1.1.8 字符串 20 1.1.9 输入输出 21 1.1.10 二分査找 28 1.1.11 展望 30 1.2 数据抽象 38 1.2.1 使用抽象数据类型 38 1.2.2 抽象数据类型举例 45 1.2.3 抽象教据类型的实现 52 1.2.4 更多抽象数据...

    算法 第4版 高清中文版

    算法(第4版)》是Sedgewick之巨著,与高德纳TAOCP一脉相承,是算法领域经典的参考书,涵盖所有程序员必须掌握的50种算法,全面介绍了关于算法和数据结构的必备知识,并特别针对排序、搜索、图处理和字符串处理进行了...

    算法,4th,塞奇威克 (Robert Sedgewick)韦恩 (Kevin Wayne), 谢路云 译.azw3

    内容全面:全面论述排序、搜索、图处理和字符串处理的算法和数据结构,涵盖每位程序员应知应会的50种算法。 全新修订的代码:全新的Java实现代码,采用模块化的编程风格,所有代码均可供读者使用。 与实际应用相结合...

    freemarker总结

    html:对字符串进行HTML编码 cap_first:使字符串第一个字母大写 lower_case:将字符串转换成小写 upper_case:将字符串转换成大写 trim:去掉字符串前后的空白字符 下面是集合的常用内建函数 size:获取序列中元素...

Global site tag (gtag.js) - Google Analytics