java字符转码

来源:互联网 发布:如何雇佣网络水军价格 编辑:程序博客网 时间:2024/06/07 01:44
java虚拟机默认的编码是unicode指的是内存中的编码是unicode,而进行io(包括网络和硬盘)传输时另外编码,通过 System.getProperty("file.encoding")查看,通常,默认为ansi,不过通过eclipse可以配置为其他编码,记为charSet;当以reader或者writer方式读写时,会自动按照配置的方式转换成unicode,而当以stream的方式读写时,不会转换,因此,如果硬盘上的字符如果不是以charSet存储,则出现乱码。
内存中编码转换方法:
string.getByte("gbk");把内存中的unicode字符转换成gbk字节
new String(byte[],"utf-8");报byte中的字节按照utf-8进行解码,转换成unicode

与文件交互转换方法:
BufferedReader br=new BufferedReader(ner InputStreamReader(new FileInputStream(path),charSet));
charSet值的就是文件保存的字符集,最好通过System.getProperty(file.encoding获得);
writer类似;

对于发送数据,服务器按照response.setCharacterEncoding—contentType—pageEncoding的优先顺序,对要发送的数据进行编码。

不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。

汉字区位码和unicode是规定怎么表示文字的,汉字内码和UTF是规定怎么(在硬盘)存储和传送文字的,后者是前者的实际实现方式,ucnicode也可以存储字符,但比较占空间。
url编码就是一个字符ascii码的十六进制。不过在每个字节前面加上了"%";其中多字节字符由于最高位是1,因此它要先被转成UTF-8

当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。
开头字节 Charset/encoding(即BOM),如下表:
EF BB BF           UTF-8
FE FF                UTF-16/UCS-2, little endian
FF FE                UTF-16/UCS-2, big endian
FF FE 00 00       UTF-32/UCS-4, little endian.
00 00 FE FF       UTF-32/UCS-4, big-endian. 

big endian更接近人类思考,但x86采用的是little endian,即在寄存器中是得字节在前,便于cpu读写
*****************************************************************************************************
unicode:
有两套标准:
UCS-2(Unicode-16)用2个字节为字符编码
UCS-4(Unicode-32)用4个字节为字符编码。
但是0xFFFF以上的字符尚未定义,因此目前说unicode主要指ucs-2(bmp)

UTF意为Unicode文本格式。对于UTF,是这样定义的:
(1)0x0000到0x007F (前9位0,ascii)则用1个字节表示,这个字节的首位是“0”,剩下的7位与原字符中的后7位相同
(2)0x0080到x07FF (前5位0 )则用2个字节表示,首字节“110”开头,后5位与原编码除去5个零后的高5位同;次字节以“10”开头,后6位与原编码的低6位相同
(3)0x0800到0xFFFF    则用三个字节表示。首节以 “1110”开头,后4位为原编码的高4位;第二个字节以“10”开头,后6位为原编码中间的6位;第三个字节以“10”开头,后6位为原编码的低6位;
简化如下:ASCII字母继续使用1字节储存,重音文字、希腊字母或西里尔字母等使用2字节来储存,而常用的汉字就要使用3字节。辅助平面字符则使用4字节。

或:
1. 对英文,仍然和ASCII一样用1个字节表示,这个字节的值小于128(\x80);
2. 对其他语言的用一个值位于128-256之间的字节开始,再加后面紧跟的2个字节表示,一个字符一共是3个字节;
**************************************************************************************
ISO-8859-n系列都是单字节字符,不同的n表示扩展不同类型的字母,比如其他西欧字母,希腊字母等
ISO-8859-1:理解为ascii的扩展,容纳256种字符,以字节为单位,解释时,每个字节直接加上8位0就变成相应的Unicode字符。解释gbk中文时,要拆分成两个字节,就变成两个Unicode,出现乱码。
GB2312:区位码+0xA0得到。“高位字节”使用了0xA1-0xF7(把0x01-0x57区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把0x01-0x5E加上0xA0)。
GB2312 支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的 GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字

狭义的ascii指1-127之间的字符,广义的ascii指的是iso-8859-1

****************************************************************************
在java中,内存中字符串以unicode保存,因此对于读取文件得到的java字符乱码,可先通过byte[] b=str.getByte("iso-8859-1");还原成"iso-8851",即ascii,然后通过new String(b,"gbk");即可得到完整的unicode字符串。

当页面中的表单提交字符串时,首先把字符串按照当前页面的编码,转化成字节串。然后再将每个字节转化成 "%XX" 的格式提交到 Web 服务器。比如,一个编码为 GB2312 的页面,提交 "中" 这个字符串时,提交给服务器的内容为 "%D6%D0"。
在服务器端,Web 服务器把收到的 "%D6%D0" 转化成 [0xD6, 0xD0] 两个字节,即当提交 "%D6%D0" 给 Tomcat 服务器时,request.getParameter() 将返回 [0x00D6, 0x00D0] 两个 UNICODE 字符,而不是返回一个 "中" 字符。因此,我们需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字节串,再用 string = new String(bytes, "GB2312") 重新得到正确的字符串 "中"。

<%@ page pageEncoding="GB2312%>指的是本页面将要在硬盘中存储的格式,如果为iso-8859-1而且文中有中文,由于eclipse内存中是unicode编码,所以暂时显示,但是保存时要保存成iso-8859-1,则会提示格式错误.
<%@ page contentType="txt/heml/charset=gb2312"%>指的是当本文档显示到用户浏览器上时,以那种编码显示。如果用户看到乱码,说明用户浏览器的设定解码方式和这个值不符。 在xx_jsp.java中,这句话被翻译成response.setContentType("text/html;charset=gb2312");
<%@request.setCharacterEncoding("text/html;charset=gb2312")%>;注意是request,他的作用是通知服务器本页面传递的参数要用gb2312解码。
在servlet中:
request.setCharacterEncoding("gb2312");表示要用此方式解析用户传过来的变量,注意,要和<%@request.setCharacterEncoding("text/html;charset=gb2312")%>对应。
response.setContentType("text/html;charset=gb2312");表示想浏览器回应时的编码方式,和<%@ page contentType="txt/heml/charset=gb2312"%>的作用相同。


转码流程:文件(gbk)-->解码-->编码--->文件(utf-8)

 

注:如有问题请留言

 

下面具体的实例

 

方法一:java.lang.String

 

Java代码  收藏代码
  1. 用于解码的构造器:  
  2. String(byte[] bytes, int offset, int length, String charsetName)   
  3. String(byte[] bytes, String charsetName)   
  4.   
  5. 用于编码的方法:  
  6. byte[] getBytes(String charsetName)  //使用指定字符集进行编码  
  7.  byte[] getBytes() //使用系统默认字符集进行编码  
  8.    

 

Java.lang.string转码代码  收藏代码
  1. public void convertionString() throws UnsupportedEncodingException{  
  2.         String s = "清山";  
  3.         byte[] b = s.getBytes("gbk");//编码  
  4.         String sa = new String(b, "gbk");//解码:用什么字符集编码就用什么字符集解码  
  5.         System.out.println(sa);  
  6.           
  7.         b = sa.getBytes("utf-8");//编码  
  8.         sa = new String(b, "utf-8");//解码  
  9.         System.err.println(sa);  
  10.     }  

方法二:java.io.InputStreamReader/OutputStreamWriter:桥转换

 

Java代码  收藏代码
  1. package com.qingshan.io;  
  2.   
  3. import java.io.FileInputStream;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.io.OutputStream;  
  9. import java.io.OutputStreamWriter;  
  10. import java.io.UnsupportedEncodingException;  
  11.   
  12. /** 
  13.  * <pre> 
  14.  * 使用java.io桥转换:对文件进行转码 
  15.  * </pre> 
  16.  * <hr Color="green" ></hr>  
  17.  * 2012 Qingshan Group 版权所有 
  18.  * <hr Color="green" ></hr>  
  19.  * @author  thetopofqingshan 
  20.  * @version 1.0.0 
  21.  * @since   JDK 1.5 
  22.  * @date    2012-4-28 
  23.  */  
  24. public class CharsetConvertion {  
  25.     private FileInputStream fis;// 文件输入流:读取文件中内容  
  26.     private InputStream is;  
  27.     private InputStreamReader isr;  
  28.     private OutputStream os;  
  29.     private OutputStreamWriter osw;//写入  
  30.     private char[] ch = new char[1024];  
  31.     public  void convertionFile() throws IOException{  
  32.         is = new FileInputStream("C:/项目进度跟踪.txt");//文件读取  
  33.         isr = new InputStreamReader(is, "gbk");//解码  
  34.         os = new FileOutputStream("C:/项目进度跟踪_utf-8.txt");//文件输出  
  35.         osw = new OutputStreamWriter(os, "utf-8");//开始编码  
  36.         char[] c = new char[1024];//缓冲  
  37.         int length = 0;  
  38.         while(true){  
  39.             length = isr.read(c);  
  40.             if(length == -1){  
  41.                 break;  
  42.             }  
  43.             System.out.println(new String(c, 0, length));  
  44.             osw.write(c, 0, length);  
  45.             osw.flush();  
  46.         }  
  47.           
  48.     }  
  49.       
  50.     public void convertionString() throws UnsupportedEncodingException{  
  51.         String s = "清山集团";  
  52.         byte[] b = s.getBytes("gbk");//编码  
  53.         String sa = new String(b, "gbk");//解码:用什么字符集编码就用什么字符集解码  
  54.         System.out.println(sa);  
  55.           
  56.         b = sa.getBytes("utf-8");//编码  
  57.         sa = new String(b, "utf-8");//解码  
  58.         System.err.println(sa);  
  59.     }  
  60.       
  61.       
  62.   
  63.     /** 
  64.      * <pre> 
  65.      * 关闭所有流 
  66.      * </pre> 
  67.      * 
  68.      */  
  69.     public void close(){  
  70.         if(isr != null){  
  71.             try {  
  72.                 isr.close();  
  73.             } catch (IOException e) {  
  74.                 e.printStackTrace();  
  75.             }  
  76.         }  
  77.         if(is != null){  
  78.             try {  
  79.                 is.close();  
  80.             } catch (IOException e) {  
  81.                 // TODO Auto-generated catch block  
  82.                 e.printStackTrace();  
  83.             }  
  84.         }  
  85.           
  86.         if(osw != null){  
  87.             try {  
  88.                 osw.close();  
  89.             } catch (IOException e) {  
  90.                 // TODO Auto-generated catch block  
  91.                 e.printStackTrace();  
  92.             }  
  93.         }  
  94.           
  95.         if(os != null){  
  96.             try {  
  97.                 os.close();  
  98.             } catch (IOException e) {  
  99.                 // TODO Auto-generated catch block  
  100.                 e.printStackTrace();  
  101.             }  
  102.         }  
  103.     }  
  104.       
  105.     /** 
  106.      * <pre> 
  107.      * 用io读取文件内容 
  108.      * </pre> 
  109.      *  
  110.      * @throws IOException 
  111.      *             读取过程中发生错误 
  112.      *  
  113.      */  
  114.       
  115.     /** 
  116.      * <pre> 
  117.      *  
  118.      * </pre> 
  119.      * @param path 
  120.      * @param charset 
  121.      * @throws IOException 
  122.      * 
  123.      */  
  124.     public void read(String path, String charset) throws IOException {  
  125.         fis = new FileInputStream(path);  
  126.         isr = new InputStreamReader(fis, charset);  
  127.         while (fis.available() > 0) {  
  128.             int length = isr.read(ch);   
  129.             System.out.println(new String(ch));  
  130.         }  
  131.     }  
  132.   
  133.       
  134.     public static void main(String[] args) {  
  135.         try {  
  136.             CharsetConvertion cc = new CharsetConvertion();  
  137.             cc.convertionFile();  
  138.             cc.convertionString();  
  139.             cc.close();  
  140.         } catch (IOException e) {  
  141.             e.printStackTrace();  
  142.         }  
  143.     }  
  144. }  
 

 

方法三:java.nio.Charset

 

Java代码  收藏代码
  1. package com.qingshan.nio;  
  2.   
  3. import java.io.FileInputStream;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStreamReader;  
  7. import java.nio.ByteBuffer;  
  8. import java.nio.CharBuffer;  
  9. import java.nio.channels.FileChannel;  
  10. import java.nio.charset.Charset;  
  11. import java.nio.charset.CharsetDecoder;  
  12. import java.nio.charset.CharsetEncoder;  
  13.   
  14. /** 
  15.  * <pre> 
  16.  * 使用nio中的Charset转换字符:整个流程是文件读取-->byte-->解码(正确)-->编码--->byte-->写入文件 
  17.  * </pre> 
  18.  * <hr Color="green" > 
  19.  * </hr> 
  20.  * 2012 Qingshan Group 版权所有 
  21.  * <hr Color="green" > 
  22.  * </hr> 
  23.  *  
  24.  * @author thetopofqingshan 
  25.  * @version 1.0.0 
  26.  * @since JDK 1.5 
  27.  * @date 2012-4-27 
  28.  */  
  29. public class CharsetConvertion {  
  30.     private FileInputStream fis;// 文件输入流:读取文件中内容  
  31.     private FileChannel in;// 文件通道:双向,流从中而过  
  32.     private FileChannel out;// 文件通道:双向,流从中而过  
  33.     private FileOutputStream fos;// 文件输出流:向文件中写入内容  
  34.     private ByteBuffer b = ByteBuffer.allocate(1024 * 3);// 设置缓存区的大小  
  35.     private Charset inSet;// 解码字符集  
  36.     private Charset outSet;// 编码字符集  
  37.     private CharsetDecoder de;// 解码器  
  38.     private CharsetEncoder en;// 编码器  
  39.     private CharBuffer convertion;// 中间的字符数据  
  40.     private ByteBuffer temp = ByteBuffer.allocate(1024 * 3);// 设置缓存区的大小:临时  
  41.     private byte[] by = new byte[1024];  
  42.     private InputStreamReader isr;  
  43.     private char[] ch = new char[1024];  
  44.   
  45.     /** 
  46.      * <pre> 
  47.      *  
  48.      * </pre> 
  49.      *  
  50.      * @param src 
  51.      * @param dest 
  52.      * @throws IOException 
  53.      *  
  54.      */  
  55.     public void convertionFile_nio(String src, String dest) throws IOException {  
  56.         fis = new FileInputStream(src);  
  57.         in = fis.getChannel();  
  58.         fos = new FileOutputStream(dest);  
  59.         out = fos.getChannel();  
  60.         inSet = Charset.forName("gbk");  
  61.         outSet = Charset.forName("utf-8");  
  62.         de = inSet.newDecoder();  
  63.         en = outSet.newEncoder();  
  64.         while (fis.available() > 0) {  
  65.             b.clear();// 清除标记  
  66.             in.read(b); // 将文件内容读入到缓冲区内:将标记位置从0-b.capacity(),  
  67.                         // 读取完毕标记在0-b.capacity()之间  
  68.             b.flip();// 调节标记,下次读取从该位置读起  
  69.             convertion = de.decode(b);// 开始编码  
  70.   
  71.             temp.clear();// 清除标记  
  72.             temp = en.encode(convertion);  
  73.             b.flip(); // 将标记移到缓冲区的开始,并保存其中所有的数据:将标记移到开始0  
  74.             out.write(temp); // 将缓冲区内的内容写入文件中:从标记处开始取出数据  
  75.         }  
  76.     }  
  77.   
  78.     /** 
  79.      * <pre> 
  80.      * 测试转码是否成功, 指定字符集读取文件 
  81.      * </pre> 
  82.      *  
  83.      * @param src 
  84.      *            被复制文件全路径 
  85.      * @param charset 解码字符集 
  86.      *  
  87.      * @throws IOException 读取过程中的发生的异常 
  88.      *  
  89.      */  
  90.     public void read(String path, String charset) throws IOException {  
  91.         fis = new FileInputStream(path);  
  92.         isr = new InputStreamReader(fis, charset);  
  93.         while (fis.available() > 0) {  
  94.             int length = isr.read(ch);  
  95.             System.out.println(new String(ch));  
  96.         }  
  97.     }  
  98.   
  99.     /** 
  100.      * <pre> 
  101.      * 关闭所有流或通道 
  102.      * </pre> 
  103.      *  
  104.      */  
  105.     public void close() {  
  106.         try {  
  107.             if (in != null) {  
  108.                 in.close();  
  109.             }  
  110.         } catch (IOException e) {  
  111.             e.printStackTrace();  
  112.         }  
  113.   
  114.         try {  
  115.             if (out != null) {  
  116.                 out.close();  
  117.             }  
  118.         } catch (IOException e) {  
  119.             e.printStackTrace();  
  120.         }  
  121.   
  122.         try {  
  123.             if (fis != null) {  
  124.                 fis.close();  
  125.             }  
  126.         } catch (IOException e) {  
  127.             e.printStackTrace();  
  128.         }  
  129.   
  130.         try {  
  131.             if (fos != null) {  
  132.                 fos.close();  
  133.             }  
  134.         } catch (IOException e) {  
  135.             e.printStackTrace();  
  136.         }  
  137.     }  
  138.   
  139.     public static void main(String[] args) {  
  140.         CharsetConvertion n = new CharsetConvertion();  
  141.         try {  
  142.              n.convertionFile_nio("C:/项目进度跟踪.txt""C:/nio_write.txt");  
  143. //          n.read("C:/nio_write.txt", "utf-8");// 正确  
  144.             // n.read("C:/nio_write.txt", "gbk");//乱码  
  145.         } catch (IOException e) {  
  146.             e.printStackTrace();  
  147.         } finally {  
  148.             n.close();  
  149.         }  
  150.     }  
  151.   
  152. }  
虽然说用什么编码就要怎么解码,但是new String中其实有一个编码集转换的过程,String(bytes[],String charset),这个构造函数第一个参数传入一个字节数组,但是这个字节数组的编码集,和第二个参数的解码集其实不需要一致。有些时候我们需要实现编码集的转换,比如我们想要将一个iso8859_1编码的字符串转换成GBK,这时候我们先用String.getBytes(String charset)这里传入ISO8859_1进行编码,然后再new String在构造函数第二个参数传入GBK这时候进行解码,这样子就完成了从iso8859_1到gbk编码集的转换。