ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:157.73KB ,
资源ID:5404411      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5404411.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Java几种常见的编码格式.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Java几种常见的编码格式.docx

1、Java几种常见的编码格式Java几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言。由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元 byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解。我们可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须经过一次翻译,把它翻译成英语。这个翻译的过程就是编码。所以可以想象只要不是说英语的国家要能够使用计算机就必须要经过编码。这看起来有些霸

2、道,但是这就是现状,这也和我们国家现在在大力推广汉语一样,希望其它国家都会说汉语,以后其它的语言都翻译成汉语,我们可以把计算机中存储信息的最小单位改成汉字,这样我们就不存在编码问题了。 所以总的来说,编码的原因可以总结为: 计算机中存储信息的最小单元是一个字节即 8 个 bit,所以能表示的字符范围是 0255 个 人类要表示的符号太多,无法用一个字节来完全表示 要解决这个矛盾必须需要一个新的数据结构 char,从 char 到 byte 必须编码 如何“翻译” 明白了各种语言需要交流,经过翻译是必要的,那又如何来翻译呢?计算中提拱了多种翻译方式,常见的有 ASCII、ISO-8859-1、G

3、B2312、GBK、UTF-8、UTF-16 等。它们都可以被看作为字典,它们规定了转化的规则,按照这个规则就可以让计算机正确的表示我们的字符。目前的编码格式很多,例如 GB2312、GBK、UTF-8、UTF-16 这几种格式都可以表示一个汉字,那我们到底选择哪种编码格式来存储汉字呢?这就要考虑到其它因素了,是存储空间重要还是编码的效率重要。根据这些因素来正确选择编码格式,下面简要介绍一下这几种编码格式。 ASCII 码 学过计算机的人都知道 ASCII 码,总共有 128 个,用一个字节的低 7 位表示,031 是控制字符如换行回车删除等;32126 是打印字符,可以通过键盘输入并且能够显

4、示出来。 ISO-8859-1 128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所有应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。 GB2312 它的全称是信息交换用汉字编码字符集 基本集,它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。 GBK 全称叫汉字内码扩展规范,是国家技术监

5、督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。 GB18030 全称是信息交换用汉字编码字符集,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。 UTF-16 说到 UTF 必须要提到 Unicode(Universal C

6、ode 统一码),ISO 试图想创建一个全新的超语言字典,世界上所有的语言都可以通过这本字典来相互翻译。可想而知这个字典是多么的复杂,关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础,下面详细介绍 Unicode 在计算机中的存储形式。 UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大

7、简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。 UTF-8 UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 16 个字节组成。 UTF-8 有以下编码规则: 如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编

8、码已经是 UTF-8 了。 如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。 如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节 Java 中需要编码的场景 前面描述了常见的几种编码格式,下面将介绍 Java 中如何处理对编码的支持,什么场合中需要编码。 I/O 操作中存在的编码 我们知道涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以

9、 Web 应用为例介绍。下图是 Java 中处理 I/O 问题的接口: Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到字符的转换,而具体字节到字符的解码实现它由 StreamDecoder 去实现,在 StreamDecoder 解码过程中必须由用户指定 Charset 编码格式。值得注意的是如果你没有指定 Charset,将使用本地环境中的默认字符集,例如在中文环境中将使用 GBK 编码。 写的情况也是类似,字符的父类是 Writer

10、,字节的父类是 OutputStream,通过 OutputStreamWriter 转换字符到字节。如下图所示: 同样 StreamEncoder 类负责将字符编码成字节,编码格式和默认编码规则与解码是一致的。 如下面一段代码,实现了文件的读写功能: Java代码 1. Stringfile=c:/stream.txt; 2. Stringcharset=UTF-8; 3. /写字符换转成字节流 4. FileOutputStreamoutputStream=newFileOutputStream(file); 5. OutputStreamWriterwriter=newOutputStr

11、eamWriter( 6. outputStream,charset); 7. try 8. writer.write(这是要保存的中文字符); 9. finally 10. writer.close(); 11. 12. /读取字节转换成字符 13. FileInputStreaminputStream=newFileInputStream(file); 14. InputStreamReaderreader=newInputStreamReader( 15. inputStream,charset); 16. StringBufferbuffer=newStringBuffer(); 17

12、. charbuf=newchar64; 18. intcount=0; 19. try 20. while(count=reader.read(buf)!=-1) 21. buffer.append(buffer,0,count); 22. 23. finally 24. reader.close(); 25. String file = c:/stream.txt; String charset = UTF-8; / 写字符换转成字节流 FileOutputStream outputStream = new FileOutputStream(file); OutputStreamWrite

13、r writer = new OutputStreamWriter( outputStream, charset); try writer.write(这是要保存的中文字符); finally writer.close(); / 读取字节转换成字符 FileInputStream inputStream = new FileInputStream(file); InputStreamReader reader = new InputStreamReader( inputStream, charset); StringBuffer buffer = new StringBuffer(); cha

14、r buf = new char64; int count = 0; try while (count = reader.read(buf) != -1) buffer.append(buffer, 0, count); finally reader.close(); 在我们的应用程序中涉及到 I/O 操作时只要注意指定统一的编解码 Charset 字符集,一般不会出现乱码问题,有些应用程序如果不注意指定字符编码,中文环境中取操作系统默认编码,如果编解码都在中文环境中,通常也没问题,但是还是强烈的不建议使用操作系统的默认编码,因为这样,你的应用程序的编码格式就和运行环境绑定起来了,在跨环境下很

15、可能出现乱码问题。 内存中操作中的编码 在 Java 开发中除了 I/O 涉及到编码外,最常用的应该就是在内存中进行字符到字节的数据类型的转换,Java 中用 String 表示字符串,所以 String 类就提供转换到字节的方法,也支持将字节转换为字符串的构造函数。如下代码示例: Java代码 1. Strings=这是一段中文字符串; 2. byteb=s.getBytes(UTF-8); 3. Stringn=newString(b,UTF-8);String s = 这是一段中文字符串; byte b = s.getBytes(UTF-8); String n = new String

16、(b,UTF-8); 另外一个是已经被被废弃的 ByteToCharConverter 和 CharToByteConverter 类,它们分别提供了 convertAll 方法可以实现 byte 和 char 的互转。如下代码所示: Java代码 1. ByteToCharConvertercharConverter=ByteToCharConverter.getConverter(UTF-8); 2. charc=charConverter.convertAll(byteArray); 3. CharToByteConverterbyteConverter=CharToByteConver

17、ter.getConverter(UTF-8); 4. byteb=byteConverter.convertAll(c); ByteToCharConverter charConverter = ByteToCharConverter.getConverter(UTF-8); char c = charConverter.convertAll(byteArray); CharToByteConverter byteConverter = CharToByteConverter.getConverter(UTF-8); byte b = byteConverter.convertAll(c);

18、 这两个类已经被 Charset 类取代,Charset 提供 encode 与 decode 分别对应 char 到 byte 的编码和 byte 到 char 的解码。如下代码所示: Java代码 1. Charsetcharset=Charset.forName(UTF-8); 2. ByteBufferbyteBuffer=charset.encode(string); 3. CharBuffercharBuffer=charset.decode(byteBuffer);Charset charset = Charset.forName(UTF-8); ByteBuffer byteB

19、uffer = charset.encode(string); CharBuffer charBuffer = charset.decode(byteBuffer); 编码与解码都在一个类中完成,通过 forName 设置编解码字符集,这样更容易统一编码格式,比 ByteToCharConverter 和 CharToByteConverter 类更方便。 Java 中还有一个 ByteBuffer 类,它提供一种 char 和 byte 之间的软转换,它们之间转换不需要编码与解码,只是把一个 16bit 的 char 格式,拆分成为 2 个 8bit 的 byte 表示,它们的实际值并没有被

20、修改,仅仅是数据的类型做了转换。如下代码所以: Java代码 1. ByteBufferheapByteBuffer=ByteBuffer.allocate(1024); 2. ByteBufferbyteBuffer=heapByteBuffer.putChar(c);ByteBuffer heapByteBuffer = ByteBuffer.allocate(1024); ByteBuffer byteBuffer = heapByteBuffer.putChar(c); 以上这些提供字符和字节之间的相互转换只要我们设置编解码格式统一一般都不会出现问题。 Java 中如何编解码 前面介绍

21、了几种常见的编码格式,这里将以实际例子介绍 Java 中如何实现编码及解码,下面我们以“I am 君山”这个字符串为例介绍 Java 中如何把它以 ISO-8859-1、GB2312、GBK、UTF-16、UTF-8 编码格式进行编码的。 Java代码 1. publicstaticvoidencode() 2. Stringname=Iam君山; 3. toHex(name.toCharArray(); 4. try 5. byteiso8859=name.getBytes(ISO-8859-1); 6. toHex(iso8859); 7. bytegb2312=name.getBytes

22、(GB2312); 8. toHex(gb2312); 9. bytegbk=name.getBytes(GBK); 10. toHex(gbk); 11. byteutf16=name.getBytes(UTF-16); 12. toHex(utf16); 13. byteutf8=name.getBytes(UTF-8); 14. toHex(utf8); 15. catch(UnsupportedEncodingExceptione) 16. e.printStackTrace(); 17. 18. public static void encode() String name = I

23、am 君山; toHex(name.toCharArray(); try byte iso8859 = name.getBytes(ISO-8859-1); toHex(iso8859); byte gb2312 = name.getBytes(GB2312); toHex(gb2312); byte gbk = name.getBytes(GBK); toHex(gbk); byte utf16 = name.getBytes(UTF-16); toHex(utf16); byte utf8 = name.getBytes(UTF-8); toHex(utf8); catch (Unsupp

24、ortedEncodingException e) e.printStackTrace(); 我们把 name 字符串按照前面说的几种编码格式进行编码转化成 byte 数组,然后以 16 进制输出,我们先看一下 Java 是如何进行编码的。 下面是 Java 中编码需要用到的类图 图 1. Java 编码类图 首先根据指定的 charsetName 通过 Charset.forName(charsetName) 设置 Charset 类,然后根据 Charset 创建 CharsetEncoder 对象,再调用 CharsetEncoder.encode 对字符串进行编码,不同的编码类型都会对

25、应到一个类中,实际的编码过程是在这些类中完成的。下面是 String. getBytes(charsetName) 编码过程的时序图 图 2.Java 编码时序图 从上图可以看出根据 charsetName 找到 Charset 类,然后根据这个字符集编码生成 CharsetEncoder,这个类是所有字符编码的父类,针对不同的字符编码集在其子类中定义了如何实现编码,有了 CharsetEncoder 对象后就可以调用 encode 方法去实现编码了。这个是 String.getBytes 编码方法,其它的如 StreamEncoder 中也是类似的方式。下面看看不同的字符集是如何将前面的字符

26、串编码成 byte 数组的? 如字符串“I am 君山”的 char 数组为 49 20 61 6d 20 541b 5c71,下面把它按照不同的编码格式转化成相应的字节。 按照 ISO-8859-1 编码 字符串“I am 君山”用 ISO-8859-1 编码,下面是编码结果: 从上图看出 7 个 char 字符经过 ISO-8859-1 编码转变成 7 个 byte 数组,ISO-8859-1 是单字节编码,中文“君山”被转化成值是 3f 的 byte。3f 也就是“?”字符,所以经常会出现中文变成“?”很可能就是错误的使用了 ISO-8859-1 这个编码导致的。中文字符经过 ISO-8

27、859-1 编码会丢失信息,通常我们称之为“黑洞”,它会把不认识的字符吸收掉。由于现在大部分基础的 Java 框架或系统默认的字符集编码都是 ISO-8859-1,所以很容易出现乱码问题,后面将会分析不同的乱码形式是怎么出现的。 按照 GB2312 编码 字符串“I am 君山”用 GB2312 编码,下面是编码结果: GB2312 对应的 Charset 是 sun.nio.cs.ext. EUC_CN 而对应的 CharsetDecoder 编码类是 sun.nio.cs.ext. DoubleByte,GB2312 字符集有一个 char 到 byte 的码表,不同的字符编码就是查这个码

28、表找到与每个字符的对应的字节,然后拼装成 byte 数组。查表的规则如下: Java代码 1. c2bc2bIndexchar8+(char&0xff) c2bc2bIndexchar 8 + (char & 0xff) 如果查到的码位值大于 oxff 则是双字节,否则是单字节。双字节高 8 位作为第一个字节,低 8 位作为第二个字节,如下代码所示: Java代码 1. if(bb0xff)/DoubleByte 2. if(dl-dp8); 5. dadp+=(byte)bb; 6. else/SingleByte 7. if(dl-dp 0xff) / DoubleByte if (dl - dp 8);

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1