编码问题一直是一个困扰程序员的问题,尤其是对于java程序员。因为java的跨平台特性,经常需要在多个编码之间进行转换。

下面详细讲一讲java中的编码问题

一、为什么要编码

长话短说,原因如下:

1,计算机存储信息的最小单位是字节Byte。占8个二进制位。所以一个字节能表示的状态只有255中

2,人类语言的符号太多,255位不够

3,所以必须把多个字节合起来表示一个人类语言符号

4,在怎么组合字节上出现了多种方法,这就是编码

二、常用编码格式

现在的编码格式有很多,常见的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。

能表示汉字的有GB2312、GBK、UTF-8、UTF-16 这几种。不同的编码格式在存储空间和编码效率方面都有不同。

如何选择,需要多方考虑。

先简单介绍一下这几种编码。

ASCII 码

最基础的编码格式,标准ASCII码只有127个。连一个字节都没用完,只用了低7位。

后来又除了扩展ASCII码把第8位利用了起来。不过总的来说,能表示的字符非常有限。

仅适用于英语系语种

属于单子节编码格式。

ISO-8859-1

这个就是上面说的扩展ASCII码。向下兼容标准ASCII码

虽然只能表示256个字符,但是已经包含了绝大多数西欧语言,所以使用上还是非常广泛的。

GB2312

全称是《信息交换用汉字编码字符集 基本集》,请注意这个基本字眼。它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。

GBK

全称叫《汉字内码扩展规范》。另一个名字叫扩展GB2312。所以你就知道了,GBK是GB2312的扩展,能表示 21003 个汉字。向下兼容GB2312,所以用GB2312编码的汉字用GBK来解码是没有问题的。

GBK是双字节的,不论编码英文字母还是汉字都是双字节的。

GB18030(兼容GB2312)

全称是《信息交换用汉字编码字符集》,是我国的强制标准,它是可变字节的,可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际系统中使用的并不广泛。

Unicode 编码方案

看了这么多编码,很烦对吧。所以国际标准化组织ISO制定了Unicode 编码方案,可以容纳世界上所有文字和符号的字符编码。

这里要多说一句,Unicode仅仅是一个字符集,规定了一个人类字符对应的二进制数。至于这个二进制数的存储方案,是不管的,由其他开发者实现。这个组织只出标准,不出实现。

所以流行的Unicode 编码方案有两种UTF-16和UTF-8。其实还有一个UTF-32,用的少。。

UTF-32

32很好理解,就是32位,定长4个字节。不管什么字符,统统32位。

好处好坏处很明显。效率高(不需要做任何编码计算转换),但是浪费空间。空间换时间。

UTF-8

这个8不是8位的意思,而是最少8位。UTF-8是一种变长的编码方式。使用 1~6 个字节来存储;

对于英语等西欧语系,非常喜欢UTF-8。因为他们只需要一个字节即可,

在单子节的情况下和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的

但是对于中日韩语系来说,就比较难受,不仅要忍受效率的损失,而且存储空间也没有节省

UTF-16

UTF-16是介于两者之间的一个编码格式。算是一种折中。折中编码会固定2字节或者4字节

具体来说是对于 Unicode 编号范围在 0000 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。

对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储

注意,只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因为它们没有单字节编码。

所以 UTF-8 和 UTF-16/32 都各有优缺点,因此选择的时候应当立足于实际的应用场景。实际上,我们在普通的应用开发中,基本不太关系这个。99%的场景是直接使用了UTF-8。我认为这并没有多大问题,UTF-8的变长特性,决定了以后即使继续增加人类语言字符,utf-8都可以放下,反观utf-16/32可能会有问题。

Java中的编解码

编码解码主要发生在字符和字节的转换过程中,这个场景一般就是IO,包括磁盘IO和网络IO

io中的编解码

解码就是由字节到字符的转换,如从网络上拿来的二进制流,转换成汉字。

Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到字符的转换,而具体字节到字符的解码实现它由 StreamDecoder 去实现,在 StreamDecoder 解码过程中必须由用户指定 Charset 编码格式。值得注意的是如果你没有指定 Charset,将使用本地环境中的默认字符集,例如在中文环境中将使用 GBK 编码。

写的情况也是类似,写字符的父类是 Writer,写字节的父类是 OutputStream,通过 OutputStreamWriter 转换字符到字节。如下图所示:

同样 StreamEncoder 类负责将字符编码成字节,编码格式和默认编码规则与解码是一致的。

写个代码测试一下:

public class IOTest {@Test public void testWrite() throws Exception { String file = "d:/test1.txt"; String charset = "UTF-8"; // 写字符换转成字节流 FileOutputStream outputStream = new FileOutputStream(file); OutputStreamWriter writer = new OutputStreamWriter( outputStream, charset); try { writer.write("保存点中文字符"); } finally { writer.close(); } } @Test public void testRead() throws Exception { String file = "d:/test1.txt"; String charset = "UTF-8"; // 读取字节转换成字符 FileInputStream inputStream = new FileInputStream(file); InputStreamReader reader = new InputStreamReader( inputStream, charset); StringBuffer buffer = new StringBuffer(); char[] buf = new char[64]; int count = 0; try { while ((count = reader.read(buf)) != -1) { buffer.append(buf, 0, count); } } finally { reader.close(); } System.out.println(buffer.toString()); }}

你可以改下字符集,多测几次。读写使用不同的字符集会乱码。

我们在写代码的时候,一定要手动指定下字符集,不要使用默认。虽然在一台机器上,不会出问题。一旦涉及到跨机器可能有异常。

我们可以看下默认的字符集到底是啥。

这是jdk的源码。在vm启动时,找有没有配file.encoding参数,配了,去找对应的字符集。如果字符集比较特殊,在不同的机器上有可能找不到的。否则就是UTF-8

/*** Returns the default charset of this Java virtual machine. * *

The default charset is determined during virtual-machine startup and * typically depends upon the locale and charset of the underlying * operating system. * * @return A charset object for the default charset * * @since 1.5 */public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { String csn = AccessController.doPrivileged( new GetPropertyAction("file.encoding")); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; else defaultCharset = forName("UTF-8"); } } return defaultCharset;}

java代码中的编解码

除了io之外,我们也经常在代码中进行string和byte的转换。

String s = "中文字符串";byte[] b = s.getBytes("UTF-8");String n = new String(b,"UTF-8");

随手指定字符集是个好习惯

java中编码问题_[干货预警]一次搞懂Java中的编码问题相关推荐

  1. java 文本工具类_干货:排名前16的Java工具类

    原标题:干货:排名前16的Java工具类 作者丨Java技术栈 https://www.jianshu.com/p/9e937d178203 在Java中,工具类定义了一组公共方法,这篇文章将介绍Ja ...

  2. java开发工具排名_干货:排名前16的Java工具类

    在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类.以下工具类.方法按使用流行度排名,参考数据来源于Github上随机选取的5万个开源项目源码. 一. ...

  3. java 线程状态监控_干货:教你如何监控 Java 线程池运行状态

    之前写过一篇 Java 线程池的使用介绍文章<线程池全面解析>,全面介绍了什么是线程池.线程池核心类.线程池工作流程.线程池分类.拒绝策略.及如何提交与关闭线程池等. 但在实际开发过程中, ...

  4. java 整数变负数_一文帮你读懂Java整数的存储原理

    前言 大家应该都知道,整数包括负数,零,和正数.在Java中,基本类型中byte(8位).short(16位).int(32位).long(64位)属于整数,并且没有无符号数,均是有符号的.对于计算机 ...

  5. 在内存中建立文件_磁盘与文件,搞懂它

    说一说计算机中的非常重要的两个东西磁盘和文件.搞清楚这两个东西有利于我们理解高级语言中关于I/O流操作的设计.它就像一把大杀器一样,无往而不利. 想一想,磁盘作为一个电脑中的硬件设备,操作系统是如何管 ...

  6. python中的dict函数什么意思_3分钟搞懂Python中dict函数的含义是什么

    Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例子,假设要根据同学的名字查找对应的 ...

  7. java 自旋锁_搞懂Java中的自旋锁

    轻松搞懂Java中的自旋锁 前言 在之前的文章<一文彻底搞懂面试中常问的各种"锁">中介绍了Java中的各种"锁",可能对于不是很了解这些概念的同学 ...

  8. python中gbk字符原因报错_不想再被鄙视?那就看进来! 一文搞懂 Python 2 字符编码...

    原标题:不想再被鄙视?那就看进来! 一文搞懂 Python 2 字符编码 程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广, ...

  9. JVM - 结合代码示例彻底搞懂Java内存区域_对象在堆-栈-方法区(元空间)之间的关系

    文章目录 Pre 示例demo 总体关系 代码示例论证 反汇编 Pre JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器 中我们探讨了线程栈中的内部结构 ,大家 ...

最新文章

  1. Google 排名第一的语言,引数十万人关注:搞定它,技术大牛都甘拜下风
  2. .NET福利集锦【持续整理中】
  3. can使能上拉 gpio_IMX6ULL 的 GPIO 操作方法
  4. VS2019 + Qt ERROR MSB4181 QtRunwork 返回了false,但未记录错误
  5. JAVA语言基础-面向对象(方法重写概述及其应用)
  6. 寻找大富翁(堆排序)
  7. STM32CubeMx + HighSpeed USB + FreeRTOS
  8. 成功解决Collecting package metadata (current_repodata.json): failedCondaHTTPError: HTTP 000 CONNECTION
  9. python语言eval_Python中的 eval 函数
  10. 生活随记-如何健康摄入果糖
  11. 6.26CF模拟赛D:黑白条题题解
  12. 什么是散列表(Hash Table)
  13. 地图APP的产品分析-驴迹导游
  14. 正则表达式在线生成器(txt2re)
  15. 赠书活动 | 数据挖掘经典入门
  16. PHP程序设计基础教程pdf
  17. spi.service.contexts.ParameterExpansionContext.findAnnotation(Ljava/lang/Class;)
  18. 大疆无人机推流至EasyCVR平台出现画面模糊是什么原因?
  19. 湖北计算机二级考试c语言报名时间,全国计算机二级考试2019年9月份报名须知
  20. 运用超链接访问自建网站

热门文章

  1. 程序员如何掌握新技术与时俱进
  2. gduuu 中旅 他最恨的是猎人
  3. 为了实现自己的美好程序人生
  4. 无聊 乱写写 CSDN博客挺好玩的 确实
  5. 飞鸽传书文件传输实现原理
  6. C程序设计基础之多维数组的指针变量
  7. 使窗体拥有透明效果的API
  8. 现在的编程语言越来越多,为什么 C 和 C++ 还没有被现在的时代淘汰呢?
  9. 北妈每日一题:到底谁养了我的鱼!
  10. string类的erase函数属于stl吗_C++ STL快速入门