《深入分析JavaWeb技术内幕》读书笔记——中文编码

为什么要编码

在计算机中存储信息的最小单元是1个字节(8bit),所以能表示的字符范围是0-255个。人类要表达的字符太多,无法用1个字节完全表示。要解决这个问题需要使用新的数据结构char,从char到byte必须编码。

编码格式

ASCII码:共128个,用一个字节的低7位表示,0-31控制字符,32-126打印字符。

ISO-8859-1:拓展自ASCII码,覆盖大多数西欧语言字符,单字节编码,共能表示256个字节。

GB2312:双字节编码,包含6763个汉字。

GBK:拓展自GB2312,和GB2312兼容,能表示21003个汉字。

GB18030:可能单字节、双字节或四字节,应用不广泛。

UTF-16:具体定义了Unicode字符在计算机中的存取方法。定长,使用两个字节表示任何字符。Java以UTF-16作为内存的字符存储格式。

UTF-8:采用变长技术,每个编码区域有不同的字码长度。中文一般占三个字节。

Java中的编码操作

I/O操作:

InputStreamReader类是关联字节到字符的桥梁,负责在I/O过程中处理读取字节到字符的转换,其委托StreamDecoder实现字节到字符的节码实现,解码过程中必须由用户指定Charset编码格式,默认使用本地环境中的默认字符集(中文环境即为GBK)。

OutputStreamWriter负责转换字符到字节,编码格式和默认编码规则与解码一致。

建议不使用操作系统的默认编码,这样会使应用程序的编码格式和运行环境绑定起来,在跨环境会出现乱码问题。

    @Test
    public void testCopyFile(){
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\Test.txt"),"UTF-8"));
         BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\Test_.txt"),"UTF-8")); )       {
            String str = null;
            int i = 0;
            while((str = reader.readLine()) != null){
                if (i != 0)
                    writer.write("\r\n");
                i++;
                writer.write(str);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

内存操作:

String str = "中文字符串";
String newStr = new String(str.getBytes(),"UTF-8");
String string = "中文字符串";
Charset charset = Charset.forName("UTF-8");
ByteBuffer byteBuffer = charset.encode(string);
CharBuffer charBuffer = charset.decode(byteBuffer); 

补充:

  • String → ByteBuffer:Charset.encode()
  • ByteBuffer → String:Charset.decode().toString()
  • CharBuffer→ String :toString()
  • ByteBuffer → byte[]:array()
  • byte[] → ByteBuffer :ByteBuffer.wrap()
  • CharBuffer  → char[]:array()
  • char[] → CharBuffer:CharBuffer.wrap()

对几种编码格式的比较

UTF-16编码效率较高,从字符到字节的相互转换更加简单,适合本地磁盘和内存之间使用,可进行字符和字节的快速切换,但是不适合网络之间传输。其采用顺序编码,不能对单个字符的编码进行校验,如果中间的一个字符码值损坏,后面所有码值都受影响,相较而言UTF-8更适合网络传输。

UTF-8编码与GBK和GB2312不同,不用查码表,所以UTF-8的编码效率更高,所以在存储中文字符时采用UTF-8编码比较理想。UTF-8中单个字符损坏不会影响后面的其他字符,编码效率介于GBK和UTF-16之间,是理想的中文编码方式。

JavaWeb中设计的编解码

1.数据经过网络传输时都是以字节为单位,所有的数据都必须能够被序列化为字节。在Java中数据要被序列化,必须继承Serializable接口。

2.把整型数字1234567当作字符来存储,则采用UTF-8编码将会占用7个字节,采用UTF-16编码则会占用14个字节,但当作int类型的数字只需要4个字节。所以,只看字符本身的长度是没有意义的,即使一样的字符,采用不同的编码最终存储的大小也会不同,所以从字符到字节要看编码类型。

URL的编解码

对URL的URI部分进行解码的字符集在<Connector URIEncoding="UTF-8"/>中定义,若没有定义则以默认编码ISO-8859-1解析。有中文URL时最好把URIEncoding设置为UTF-8编码。

对于QueryString的解析:QueryString的解码字符集要么是Header中ContentType定义的Charset,要么默认是ISO-8859-1要使用ContentType中定义的编码,就要设置useBodyEncodingForURI:<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true"/>。这个配置项不是对整个URI都采用BodyEncoding编码,仅仅是对QueryString使用BodyEncoding解码。

HTTP Header编解码

客户端发起的HTTP请求除了URL外,还可能会在Header中传递其他参数(如Cookie)。对Header中的项进行解码默认使用ISO-8859-1,且不能设置Header其他的解码格式,若设置的Header中有非ASCII字符,解码中肯定会出现乱码。若一定要传递,则调用Tomcat中的URLEncoder编码,再添加到Header中。

POST表单的编解码

POST表单的参数传递方式是通过HTTP的BODY传递到服务器的,当提交时先根据ContentType中的字符集进行解码,字符集编码可以由request.setCharacterEncoding(charset)来设置。

此外务必注意:对POST表单提交参数的解码是发生在getParameter时,所以在第一次调用request.getParameter方法之前就要先设置request.setCharacterEncoding(charset)方法。

关于上传的文件编码:也是使用ContentType定义的字符集编码,不过上传文件是以字节流的方式传输到服务器的本地临时目录,此过程尚不涉及字符编码,只有当文件内容添加到parameters时才进行编码。

HTTP BODY的编解码

编解码字符集通过response.setCharacterEncoding来设置,通过Header的Content-Type返回客户端。若Header中没有Content-Type,浏览器会根据<meta http-equiv="Content-Type" content="text/html; charset=utf-8">中的charset来解码,若依然没有该属性,浏览器则使用默认编码。

补充:使用JDBC来存取数据时要和数据的内置编码保持一致,可以设置JDBC URL来指定:jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=UTF-8

时间: 2024-10-12 15:37:54

《深入分析JavaWeb技术内幕》读书笔记——中文编码的相关文章

&lt;&lt;深入分析javaWeb技术内幕&gt;&gt;读书笔记-JVM内存管理2

JVM垃圾回收策略 1.静态内存分配和回收 编译时已经确定了内存空间大小,程序被加载后则一次性分配好内存空间.程序结束后,则对应栈帧撤销,分配的静态内存空间则被回收. 2.动态内存分配和回收 程序运行动态分配内存空间,回收时则由垃圾收集器负责. 3.垃圾收集器 A.正确的检测出垃圾对象(关键功能) B.释放垃圾对象占用的内存空间 4.基于分代的垃圾收集算法(hostpot) 算法设计思路: 把对象按照寿命的长短进行分组(年轻代,年老代),新创建的对象分配在年轻代中,对象经过几次垃圾回收后,仍然存

&lt;&lt;深入分析javaWeb技术内幕&gt;&gt;读书笔记-Javac编译原理

1.javac是什么? javac是一种编译器,能将一种语言规范转化为另一种语言规范. 2.javac的任务是什么? 将java源代码语言先转化成JVM能够识别的的一种语言,然后由JVM再将JVM语言转化成当前机器识别的机器语言.表面上,将.java文件转成.class文件,而实际上是将java源代码转化成一串能被jvm识别的有格式二进制数字. 3.javac编译器的基本结构

深入分析JavaWeb技术内幕(修订版)》【PDF】下载

<深入分析JavaWeb技术内幕(修订版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062569 内容简介 <深入分析Java Web技术内幕>围绕JavaWeb相关技术从三方面全面深入地进行阐述.首先介绍前端知识,主要介绍JavaWeb开发中涉及的一些基本知识,包括Web请求过程.HTTP协议.DNS技术和CDN技术.其次深入介绍Java技术,包括I/O技术.中文编码问题.Javac编译原理.class文件结构解析.

Struts2技术内幕 读书笔记一 框架的本质

本读书笔记系列,主要针对陆舟所著<<Struts2技术内幕 深入解析Strtus2架构设计与实现原理>>一书.笔记中所用的图片若无特殊说明,就都取自书中,特此声明. 什么是框架?我们为什么要用框架?框架能给我们带来什么? 这几个问题既简单又复杂.说它简单,是因为框架确实存在在软件设计中,说它复杂是因为我们现在所使用的框架不论是spring还是struts都是经过多年的发展,其内部已经十分庞杂了,因此想一句话两句话说清楚一个框架就不是那么简单了. OK,既然现有的框架都很复杂,那我们

Struts2技术内幕 读书笔记三 表示层的困惑

表示层能有什么疑惑?很简单,我们暂时忘记所有的框架,就写一个注册的servlet来看看. index.jsp <form id="form1" name="form1" method="post" action="loginServlet"> <table width="357" border="0" align="center"> <t

Servlet工作原理(读许令波《深入分析javaWeb技术内幕》)笔记

在介绍servlet的工作原理之前首先我们要先了解一下与servlet配套的servlet容器,本文以tomcat为例 1.Tomcat容器的基础知识 Tomcat的容器是分级管理共分为四个等级从上之下为:container,engine,host,context. 而直接管理servlet的容器是context容器.在tomcat中一个context容器对应一个web app应用 2.servlet容器的启动过程 当在Tomcat中添加一个应用的时候Tomcat会创建一个standardCon

Struts2技术内幕 读书笔记二 web开发的基本模式

最佳实践 在讨论基本模式之前,我们先说说一个词:最佳实践 任何程序的编写都得遵循一个特定的规范.这种规范有约定俗称的例如:包名全小写,类名每个单词第一个字母大写等等等等;另外还有一些需要我们严格遵守的:例如我们写自己的servlet的时候就得继承javax.servlet.http.HttpServlet接口. 在标准之上的是对不同标准的具体实现.例如同是servlet标准,tomcat有一套实现方式,Websphere又有不同的实现方式. 在程序员级别来说,面对复杂的业务流程,不同的程序员会有

深入分析JavaWeb 技术内幕

1,通过浏览器请求一个资源,会发生以下几种过程 1) http的解析过程,包括对于http请求头和响应头中指令(控制用户浏览器的渲染行为和 服务器的执行逻辑)的解析 2)DNS的解析过程(根据域名获取目标ip地址的过程---也就是获取处理http请求的服务器的ip) 3)CDN工作机制(内容分布网络的工作机制)(主要是提供静态资源,占请求的大部分内容) 4)在第二步中,找到了目标ip,该服务器应该会提供动态资源返回给用户浏览器(zzy)

spring技术内幕读书笔记之IoC容器的学习

第一篇:概念和设计原理 IoC容器的实现作为Spring的核心内容之一非常有必要拿来研究一下 1.概念 IoC(Inversion of Control,控制反转)必须思考的问题:哪些方面的控制被反转了? 对于这个问题,Martin Flower给出结论是:依赖对象的获得被反转了.基于此,他为控制反转创造了一个更好的名字:依赖注入. SpringIoC模块是这一思想的一种实现,IoC容器把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,降低了组件之间的耦合度,利于功能复用,方便进行