`
jaesonchen
  • 浏览: 312935 次
  • 来自: ...
社区版块
存档分类
最新评论

java是如何编码解码的

 
阅读更多

编码&解码

在java中主要有四个场景需要进行编码解码操作:

1:I/O操作

2:内存

3:数据库

4:javaWeb

下面主要介绍前面两种场景,数据库部分只要设置正确编码格式就不会有什么问题,javaWeb场景过多需要了解URL、get、POST的编码,servlet的解码,所以javaWeb场景下节LZ介绍。

I/O操作

在前面LZ就提过乱码问题无非就是转码过程中编码格式的不统一产生的,比如编码时采用UTF-8,解码采用GBK,但最根本的原因是字符到字节或者字节到字符的转换出问题了,而这中情况的转换最主要的场景就是I/O操作的时候。当然I/O操作主要包括网络I/O(也就是javaWeb)和磁盘I/O。网络I/O下节介绍。

首先我们先看I/O的编码操作。

201412300001

InputStream为字节输入流的所有类的超类,Reader为读取字符流的抽象类。java读取文件的方式分为按字节流读取和按字符流读取,其中InputStream、Reader是这两种读取方式的超类。

按字节

我们一般都是使用InputStream.read()方法在数据流中读取字节(read()每次都只读取一个字节,效率非常慢,我们一般都是使用read(byte[])),然后保存在一个byte[]数组中,最后转换为String。在我们读取文件时,读取字节的编码取决于文件所使用的编码格式,而在转换为String过程中也会涉及到编码的问题,如果两者之间的编码格式不同可能会出现问题。例如存在一个问题test.txt编码格式为UTF-8,那么通过字节流读取文件时所获得的数据流编码格式就是UTF-8,而我们在转化成String过程中如果不指定编码格式,则默认使用系统编码格式(GBK)来解码操作,由于两者编码格式不一致,那么在构造String过程肯定会产生乱码,如下:

  1. File file = new File("C:\\test.txt");  
  2. InputStream input = new FileInputStream(file);  
  3. StringBuffer buffer = new StringBuffer();  
  4. byte[] bytes = new byte[1024];  
  5. for(int n ; (n = input.read(bytes))!=-1 ; ){  
  6.     buffer.append(new String(bytes,0,n));  
  7. }  
  8. System.out.println(buffer);  

  

输出结果:锘挎垜鏄?cm

test.txt中的内容为:我是 cm。

要想不出现乱码,在构造String过程中指定编码格式,使得编码解码时两者编码格式保持一致即可:

  1. buffer.append(new String(bytes,0,n,"UTF-8"));  

  

按字符

其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。在java中Reader是读取字符流的超类。所以从底层上来看按字节读取文件和按字符读取没什么区别。在读取的时候字符读取每次是读取留个字节,字节流每次读取一个字节。

字节&字符转换

字节转换为字符一定少不了InputStreamReader。API解释如下:InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。 每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。API解释非常清楚,InputStreamReader在底层读取文件时仍然采用字节读取,读取字节后它需要根据一个指定的编码格式来解析为字符,如果没有指定编码格式则采用系统默认编码格式。

  1. String file = "C:\\test.txt";   
  2.          String charset = "UTF-8";   
  3.          // 写字符换转成字节流  
  4.          FileOutputStream outputStream = new FileOutputStream(file);   
  5.          OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset);   
  6.          try {   
  7.             writer.write("我是 cm");   
  8.          } finally {   
  9.             writer.close();   
  10.          }   
  11.            
  12.          // 读取字节转换成字符  
  13.          FileInputStream inputStream = new FileInputStream(file);   
  14.          InputStreamReader reader = new InputStreamReader(   
  15.          inputStream, charset);   
  16.          StringBuffer buffer = new StringBuffer();   
  17.          char[] buf = new char[64];   
  18.          int count = 0;   
  19.          try {   
  20.             while ((count = reader.read(buf)) != -1) {   
  21.                 buffer.append(buf, 0, count);   
  22.             }   
  23.          } finally {   
  24.             reader.close();   
  25.          }  
  26.          System.out.println(buffer);  

  

内存

首先我们看下面这段简单的代码

  1. String s = "我是 cm";   
  2. byte[] bytes = s.getBytes();   
  3. String s1 = new String(bytes,"GBK");   
  4. String s2 = new String(bytes);  

  

在这段代码中我们看到了三处编码转换过程(一次编码,两次解码)。先看String.getTytes():

  1. public byte[] getBytes() {  
  2.         return StringCoding.encode(value, 0, value.length);  
  3.     }  

  

内部调用StringCoding.encode()方法操作:

 
  1. static byte[] encode(char[] ca, int off, int len) {  
  2.         String csn = Charset.defaultCharset().name();  
  3.         try {  
  4.             // use charset name encode() variant which provides caching.  
  5.             return encode(csn, ca, off, len);  
  6.         } catch (UnsupportedEncodingException x) {  
  7.             warnUnsupportedCharset(csn);  
  8.         }  
  9.         try {  
  10.             return encode("ISO-8859-1", ca, off, len);  
  11.         } catch (UnsupportedEncodingException x) {  
  12.             // If this code is hit during VM initialization, MessageUtils is  
  13.             // the only way we will be able to get any kind of error message.  
  14.             MessageUtils.err("ISO-8859-1 charset not available: "  
  15.                              + x.toString());  
  16.             // If we can not find ISO-8859-1 (a required encoding) then things  
  17.             // are seriously wrong with the installation.  
  18.             System.exit(1);  
  19.             return null;  
  20.         }  
  21.     }  

  

encode(char[] paramArrayOfChar, int paramInt1, int paramInt2)方法首先调用系统的默认编码格式,如果没有指定编码格式则默认使用ISO-8859-1编码格式进行编码操作,进一步深入如下:

  1. String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;  

  

同样的方法可以看到new String 的构造函数内部是调用StringCoding.decode()方法:

  1. public String(byte bytes[], int offset, int length, Charset charset) {  
  2.         if (charset == null)  
  3.             throw new NullPointerException("charset");  
  4.         checkBounds(bytes, offset, length);  
  5.         this.value =  StringCoding.decode(charset, bytes, offset, length);  
  6.     }  

  

decode方法和encode对编码格式的处理是一样的。

对于以上两种情况我们只需要设置统一的编码格式一般都不会产生乱码问题。

 

编码&编码格式

首先先看看java编码类图[1]

201412300003

首先根据指定的chart设置ChartSet类,然后根据ChartSet创建ChartSetEncoder对象,最后再调用 CharsetEncoder.encode 对字符串进行编码,不同的编码类型都会对应到一个类中,实际的编码过程是在这些类中完成的。下面时序图展示详细的编码过程:

201412300002

通过这编码的类图和时序图可以了解编码的详细过程。下面将通过一段简单的代码对ISO-8859-1、GBK、UTF-8编码

  1. public class Test02 {  
  2.     public static void main(String[] args) throws UnsupportedEncodingException {  
  3.         String string = "我是 cm";  
  4.         Test02.printChart(string.toCharArray());  
  5.         Test02.printChart(string.getBytes("ISO-8859-1"));  
  6.         Test02.printChart(string.getBytes("GBK"));  
  7.         Test02.printChart(string.getBytes("UTF-8"));  
  8.     }  
  9.       
  10.     /** 
  11.      * char转换为16进制 
  12.      */  
  13.     public static void printChart(char[] chars){  
  14.         for(int i = 0 ; i < chars.length ; i++){  
  15.             System.out.print(Integer.toHexString(chars[i]) + " ");   
  16.         }  
  17.         System.out.println("");  
  18.     }  
  19.       
  20.     /** 
  21.      * byte转换为16进制 
  22.      */  
  23.     public static void printChart(byte[] bytes){  
  24.         for(int i = 0 ; i < bytes.length ; i++){  
  25.             String hex = Integer.toHexString(bytes[i] & 0xFF);   
  26.              if (hex.length() == 1) {   
  27.                hex = '0' + hex;   
  28.              }   
  29.              System.out.print(hex.toUpperCase() + " ");   
  30.         }  
  31.         System.out.println("");  
  32.     }  
  33. }  
  34. -------------------------outPut:  
  35. 6211 662f 20 63 6d   
  36. 3F 3F 20 63 6D   
  37. CE D2 CA C7 20 63 6D   
  38. E6 88 91 E6 98 AF 20 63 6D  

  

通过程序我们可以看到“我是 cm”的结果为:

char[]:6211 662f 20 63 6d

ISO-8859-1:3F 3F 20 63 6D 
GBK:CE D2 CA C7 20 63 6D 
UTF-8:E6 88 91 E6 98 AF 20 63 6D

图如下:

201412310001


分享到:
评论

相关推荐

    tlv的java编码和解码

    - **源码包**:包含了实现TLV编码解码的Java源代码,可以学习和理解其内部实现逻辑。 - **Demo**:一个带有详细注释的示例程序,展示了如何使用这个库进行编码和解码操作,可以帮助开发者快速上手。 为了更好地利用...

    java二维码编码解码测试

    本项目名为“java二维码编码解码测试”,其核心是利用QRCoder这个Java库进行二维码的编码和解码操作。 QRCoder是一个简洁且易于使用的Java库,专门用于创建二维码。它允许开发者将各种类型的数据,如文本、URL、...

    java实现huffman编码解码

    本程序利用Java实现以下功能: 1、读取一行或多行数据,统计出现的所有字母的出现次数 2、构造huffman树 3、生成出现字母的编码表 4、对输入的数据进行...5、输入编码结果,对编码结果进行解码,得到原来的输入数据。

    java使用Hex编码解码实现Aes加密解密功能示例

    在本文示例中,我们关注的是如何利用Java的Hex编码和解码来处理AES加密和解密的过程。 首先,让我们了解什么是Hex编码。Hex编码是一种将二进制数据转换为可打印字符的表示方式,每个字节被转换为两个十六进制数字...

    java 二维码编码解码

    Java作为广泛使用的编程语言,提供了丰富的库来处理二维码的编码与解码。本文将深入探讨如何在Java环境中实现二维码的编码和解码。 首先,我们需要了解二维码编码的过程。编码是将数据转化为二维码图形的过程。在...

    Java 编码解码

    【标题】:“Java 编码解码” 在Java编程中,编码和解码是处理字符集和字节序列的关键操作。编码是指将字符转换为字节的过程,而解码则是相反的过程,即从字节恢复到字符。这些操作在处理不同语言、不同系统间的...

    java和js相互base64编码解码

    `调用.txt`文件可能是测试这两种编码解码方法的简单脚本,它会调用Java和JavaScript中的函数,并比较结果是否一致,确保在不同环境下的Base64编码和解码是兼容的。 总之,Java和JavaScript中Base64编码和解码的实现...

    Base64 编码解码 Java

    Base64 编码解码 Java ,Java对字符串Base64 编码解码的方法!!

    Java基于Base64实现编码解码图片文件

    "Java基于Base64实现编码解码图片文件" Java基于Base64实现编码解码图片文件是Java语言中的一种常见的编码解码实现方式。Base64是一种常用的字符编码,在很多地方都会用到,但它并不是安全领域下的加密解密算法,...

    Java Escape编码 解码相关实例代码.rar

    一个与Escape编码 解码相关的Java实例代码,其实是一个解码编码类,里面就一个文件。关于解码的说明:本方法保证 不论参数s是否经过escape()编码,均能得到正确的“解码”结果,编码的过程请大家下载源代码查看,本...

    二维码 java android 编码 解码 jar

    本主题主要关注Java和Android环境下的二维码编码与解码,以及涉及到的jar库,如QRcode和PDF417。 首先,二维码(Quick Response code)是一种二维条形码,能存储比传统一维条形码更多的信息,如网址、文本、联系人...

    Java Gif 编码和解码程序

    Java GIF编码和解码是计算机图形处理中的一个重要领域,特别是在网页和应用程序中处理动画和静态图像时。GIF(Graphics Interchange Format)是一种流行的位图格式,支持透明度和有限的动画功能。在Java中,处理GIF...

    js解码 、java编码

    本文将深入探讨“js解码”和“java编码”这两个主题,并结合标签“源码”和“工具”,讨论如何在实际项目中应用它们。 首先,我们来看JavaScript中的解码。JavaScript是一种在客户端和服务器端都能运行的脚本语言,...

    Java文本字符编码解码操作类 Escape.java源代码.rar

    在Java编程语言中,字符编码和解码是处理文本数据时不可或缺的部分,特别是在网络通信、文件存储或跨系统交互中。Escape.java源代码是专门设计用于处理文本字符的编码和解码操作的一个类。这个类的目标是确保无论...

    GSM-PDU模式短信编解码-java代码

    项目中用到了AT指令中的GSM短信息的收发,上网找的代码大多都是C或者C++语言编写的,因为我使用的是java语言,于是决定自己编写一套java语言的GSM-PDU模式短信息编码与解码的代码: 1、短信传输分三种模式:Block...

    java使用URLDecoder和URLEncoder对中文字符进行编码和解码

    在Java编程语言中,`URLDecoder`和`URLEncoder`是两个非常重要的工具类,主要用于处理URL中的中文字符和其他特殊...理解它们的工作原理和使用方法,能帮助开发者避免编码解码过程中的常见问题,保证数据传输的准确性。

    jother编码解码工具

    "jother编码解码工具"是一个专门用于JavaScript环境中的工具,它能够帮助开发者实现文字到标点符号的转换,这对于某些特定的文本处理任务,如信息加密、数据分析或者用户界面的特殊展示,可能是非常有用的。...

    java的二维码编码与解码

    【Java二维码编码与解码】 在Java中,二维码(QR Code)是一种常用的数据编码方式,可以存储各种类型的信息,如文本、网址、联系人信息等。这个简单的Java二维码编码与解码说明文档提供了如何在Java程序中实现这一...

    java图片编码、解码的接口中文api

    在Java编程语言中,处理图像编码和解码是常见的任务,尤其在开发验证机制如验证码时更为重要。本文将深入探讨Java中与图片编码、解码相关的API,主要聚焦于JPEG格式,因为提供的文件列表中涉及到JPEG API的相关接口...

    SNMP数据编码解码的java实现

    描述了基于SNMP协议的常用数据类型的种类及特性,按照ASN.1语法对管理信息库中悲观对象编码、解码的基本规则,用Java语言给予了实现。

Global site tag (gtag.js) - Google Analytics