java String.getBytes()编码问题——String.getBytes(charset)
String的getBytes()方法是得到一个字串的字节数组,这是众所周知的。但特别要注意的是,本方法将返回该操作系统默认的编码格式的字节数组。如果你在使用这个方法时不考虑到这一点,你会发现在一个平台上运行良好的系统,放到另外一台机器后会产生意想不到的问题。比如下面的程序:
class TestCharset {
public static void main(String[] args) {
new TestCharset().execute(); } private void execute() {
String s = "Hello!你好!"; byte[] bytes = s.getBytes(); System.out.println("bytes lenght is:" + bytes.length);
} } |
在一个中文WindowsXP系统下,运行时,结果为:
bytes lenght is:12 |
但是如果放到了一个英文的UNIX环境下运行:
$ java TestCharset bytes lenght is:9 |
如果你的程序依赖于该结果,将在后续操作中引起问题。为什么在一个系统中结果为12,而在另外一个却变成了9了呢?上面已经提到了,该方法是和平台(编码)相关的。
在中文操作系统中,getBytes方法返回的是一个GBK或者GB2312的中文编码的字节数组,其中中文字符,各占两个字节。而在英文平台中,一般的默认编码是“ISO-8859-1”,每个字符都只取一个字节(而不管是否非拉丁字符)。
Java中的编码支持
Java是支持多国编码的,在Java中,字符都是以Unicode进行存储的,比如,“你”字的Unicode编码是“4f60”,我们可以通过下面的实验代码来验证:
class TestCharset {
public static void main(String[] args) {
char c = '你'; int i = c; System.out.println(c); System.out.println(i); } } |
不管你在任何平台上执行,都会有相同的输出:
20320 |
20320就是Unicode “4f60”的整数值。其实,你可以反编译上面的类,可以发现在生成的.class文件中字符“你”(或者其它任何中文字串)本身就是以Unicode编码进行存储的:
char c = '/u4F60'; ... ... |
即使你知道了编码的编码格式,比如:
javac -encoding GBK TestCharset.java |
编译后生成的.class文件中仍然是以Unicode格式存储中文字符或字符串的。使用String.getBytes(String charset)方法
所以,为了避免这种问题,我建议大家都在编码中使用String.getBytes(String charset)方法。下面我们将从字串分别提取ISO-8859-1和GBK两种编码格式的字节数组,看看会有什么结果:
package org.bruce.file.handle.experiment;
class TestCharset3 {
public static void main(String[] args) {
new TestCharset3().execute();
}
private void execute() {
String s = "Hello!你好!";
byte[] bytesISO8859 = null;
byte[] bytesGBK = null;
try {
bytesISO8859 = s.getBytes("iso-8859-1");
bytesGBK = s.getBytes("GBK");
} catch (java.io.UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println("-------------- /n 8859 bytes:");
System.out.println("bytes is: " + arrayToString(bytesISO8859));
System.out.println("hex format is:" + encodeHex(bytesISO8859));
System.out.println();
System.out.println("-------------- /n GBK bytes:");
System.out.println("bytes is: " + arrayToString(bytesGBK));
System.out.println("hex format is:" + encodeHex(bytesGBK));
}
public static final String encodeHex(byte[] bytes) {
StringBuffer buff = new StringBuffer(bytes.length * 2);
String b;
for (int i = 0; i < bytes.length; i++) {
b = Integer.toHexString(bytes[i]);
// byte是两个字节的, 而上面的Integer.toHexString会把字节扩展为4个字节
buff.append(b.length() > 2 ? b.substring(6, 8) : b);
buff.append(" ");
}
return buff.toString();
}
public static final String arrayToString(byte[] bytes) {
StringBuffer buff = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
buff.append(bytes[i] + " ");
}
return buff.toString();
}
}
|
执行上面程序将打印出:
可见,在s中提取的8859-1格式的字节数组长度为9,中文字符都变成了“63”,ASCII码为63的是“?”,一些国外的程序在国内中文环境下运行时,经常出现乱码,上面布满了“?”,就是因为编码没有进行正确处理的结果。 而提取的GBK编码的字节数组中正确得到了中文字符的GBK编码。字符“你”“好”“!”的GBK编码分别是:“c4e3”“bac3”“a3a1”。得到了正确的以GBK编码的字节数组,以后需要还原为中文字串时,可以使用下面方法:
mysql 不支持 unicode,所以比较麻烦。
将 connectionString 设置成 encoding 为 gb2312 String connectionString = "jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=gb2312"; 测试代码: String str = "汉字"; PreparedStatement pStmt = conn.prepareStatement("INSERT INTO test VALUES (?)"); pStmt.setString(1,str); pStmt.executeUpdate(); 数据库表格: create table test ( name char(10) ) 连接 Oracle Database Server ------------------------------------------------------------------------------- 在把汉字字符串插入数据库前做如下转换操作: String(str.getBytes("ISO8859_1"),"gb2312") 测试代码: String str = "汉字"; PreparedStatement pStmt = conn.prepareStatement("INSERT INTO test VALUES (?)"); pStmt.setString(1,new String(str.getBytes("ISO8859_1"),"gb2312"); pStmt.executeUpdate(); Servlet ------------------------------------------------------------------------------- 在 Servlet 开头加上两句话: response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); JSP ------------------------------------------------------------------------------- |
@Test
public void testBytes(){
//字节数
//中文:ISO:1 GBK:2 UTF-8:3
//数字或字母: ISO:1 GBK:1 UTF-8:1
String username = "中";
try {
//得到指定编码的字节数组 字符串--->字节数组
byte[] u_iso=username.getBytes("ISO8859-1");
byte[] u_gbk=username.getBytes("GBK");
byte[] u_utf8=username.getBytes("utf-8");
System.out.println(u_iso.length);
System.out.println(u_gbk.length);
System.out.println(u_utf8.length);
//跟上面刚好是逆向的,字节数组---->字符串
String un_iso=new String(u_iso, "ISO8859-1");
String un_gbk=new String(u_gbk, "GBK");
String un_utf8=new String(u_utf8, "utf-8");
System.out.println(un_iso);
System.out.println(un_gbk);
System.out.println(un_utf8);
//有时候必须是iso字符编码类型,那处理方式如下
String un_utf8_iso=new String(u_utf8, "ISO8859-1");
//将iso编码的字符串进行还原
String un_iso_utf8=new String(un_utf8_iso.getBytes("ISO8859-1"),"UTF-8");
System.out.println(un_iso_utf8); } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
测试结果:
1
2
3
?
中
中
ä¸
中
从转载的文章摘:
乱码原因:为什么使用ISO8859-1编码再组合之后,无法还原"中"字呢,其实原因很简单,因为ISO8859-1编码的编码表中,根本就没有包含汉字字符,当然也就无法通过"中".getBytes("ISO8859-1");来得到正确的"中"字在ISO8859-1中的编码值了,所以再通过new String()来还原就无从谈起了.
有时候,为了让中文字符适应某些特殊要求(如http header头要求其内容必须为iso8859-1编码),可能会通过将中文字符按照字节方式来编码的情况,如:
String s_iso88591 = new String("中".getBytes("UTF-8"),"ISO8859-1"),这样得到的s_iso8859-1字符串实际是三个在ISO8859-1中的字符,在将这些字符传递到目的地后,目的地程序再通过相反的方式String s_utf8 = new String(s_iso88591.getBytes("ISO8859-1"),"UTF-8")来得到正确的中文汉字"中".这样就既保证了遵守协议规定、也支持中文.
转自:http://blog.csdn.net/yang3wei/article/details/7381578 http://blog.csdn.net/techbirds_bao/article/details/8555449
java String.getBytes()编码问题——String.getBytes(charset)的更多相关文章
- [转]String.getBytes()和new String()
在Java中,String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示,如 byte[] b_gbk = "中&q ...
- 通过Java编码获取String分行字符串的内容
代码案列: import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException ...
- new String(request.getParameter("userID").trim().getBytes("8859_1"))的含义是什么?
new String(request.getParameter("userID").trim().getBytes("8859_1")) request.get ...
- java String字符串编码类型转换
/** * 前后端数据乱码问题 * 解决办法1: * 乱码原因:一编一解码型不一致导致. * [main description] * @param {[type]} String[] args [d ...
- java源码解析之String类(二)
上一节主要介绍了String类的一些构造方法,主要分为四类 无参构造器:String(),创建一个空字符串"",区别于null字符串,""已经初始化,null并 ...
- java 上传MultipartFile和String post请求
/** * POST Multipart Request * @Description: * @param requestUrl 请求url * @param requestText 请求参数 * @ ...
- Java入门 - 语言基础 - 14.String类
原文地址:http://www.work100.net/training/java-string.html 更多教程:光束云 - 免费课程 String类 序号 文内章节 视频 1 概述 2 创建字符 ...
- 菜鸡的Java笔记 第十四 String 类常用方法
/*String 类常用方法 将所有String类的常用方法全部记下来,包括方法名称,参数作用以及类型 一个成熟的编程语言,除了它的语法非常完善之外,那么也需要提供有大量的开发类库 ...
- Java学习笔记19(String类)
String代表字符串,在Java中,所有的字符串字面值都作为此类的实例实现 字符串的特点以及简单的原理分析: package demo; /* * String类的特点: * 所有的"&q ...
随机推荐
- 浅析LruCache原理
Android用LruCache来取代原来强引用和软引用实现内存缓存,因为据说自2.3以后Android将更频繁的调用GC,导致软引用缓存的数据极易被释放. LruCache使用一个LinkedHas ...
- Java使用正则表达式获取文本的章节名称
获取文本的章节,首先要确定章节的开始标准,一般中文的章节都是以“第”开头,第一章.第二章等.所以使用“^”字符来确定首位,但是很多时候章节前面会有空白字符,所有以“第”作为章节的开始,进行以下的匹配 ...
- 【原】PSD图标素材的全自动切图方法,适用于IOS、安卓、web前端等领域
屌丝个人开发者经常遇到的尴尬问题是,自己不会设计UI素材又请不起专业的美工.最好的方式是去网上下载符合自己需求的素材修修改改直接用上.但是,在这个过程中会发现很多下载下来的素材是PSD格式的,很多图标 ...
- Android源码分析之HandlerThread
HandlerThread是一种特殊的Thread,也就是有Looper的thread,既然有looper的话,那我们就可以用此looper来 创建一个Handler,从而实现和它的交互,比如你可以通 ...
- XCode升级到7后,规范注释生成器VVDocumenter插件没有用了,怎么办?
Xcode更新到7之后,发现很多插件包括规范注释生成器VVDocumenter的插件都没法用了,找遍百度都没有找到成功解决这个问题的方法,然后我突发奇想,把注释也弄进代码模板里.虽然没有插件那样灵活: ...
- 转 android launch flow
Android系统开机主要经历三个阶段: bootloader启动 Linux启动 Android启动 启动文件: 对于机器从通电到加载Linux系统一般需要三个文件:bootloader(引导文件) ...
- Visual Studio发布Web项目报错:Unable to add 'xxx' to the Web site. Unable to add file 'xxx'. The specified file could not be encrypted.
背景 Visual Studio下的Web项目 现象 发布时遇到Unable to add 'xxx' to the Web site. Unable to add file 'xxx'. The ...
- Oracle查看所有用户
1.查看所有用户:select * from dba_users; select * from all_users; select * from user_users; 2.查看用户或角色系统 ...
- JS 中html 动态替换
一.定义通用替换js函数,或调用JQuery验证的$.format函数: //----通用JS操作// var a = "我喜欢吃{0},也喜欢吃{1},但是最喜欢的还是{0},偶尔再买点{ ...
- CentOS6.5(Python-2.7.12)安装Pip
1.安装setuptools(下载链接可从https://pypi.python.org/pypi/setuptools#code-of-conduct寻找) #Download setuptools ...