Java基础之IO转换流学习
- 简要概述
- 字符集
-
- 介绍
- 分类
- 乱码举例
- 转换流
-
- InputStreamReader类(字节流->字符流)
- OutputStreamWriter类(字符流->字节流)
- 注意事项
- 参考链接
简要概述
- 作用
Java基础之IO转换流学习简要概述字符集转换流参考链接 - 字符编码与解码
字符编码(Character Encoding):就是一套自然语言的字符与二进制数之间的对应规则。
编码表:则是生活中文字和计算机中二进制的对应规则。
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。
编码:按照某种规则,将字符存储到计算机中(字符(能看懂的)–字节(看不懂的))
解码:将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码(字节(看不懂的)–>字符(能看懂的))
// 编码:通过指定的字符集解码字节数组 byte[] -- String public String(byte bytes[], String charsetName) throws UnsupportedEncodingException { this(bytes, 0, bytes.length, charsetName); } // 解码:使用指定的字符集合把字符串编码为字节数组 String -- byte[] public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, value, 0, value.length); }
字符集
介绍
-
概念
字符集(Charset):也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。
计算机要准确的存储和识别各种字符集符合,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
当指定了编码,它对应的字符集自然就指定了。
分类
-
ASCII字符集
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
-
ISO-8859-1字符集
拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
ISO-8859-1使用单字节编码,兼容ASCII编码。
-
GBxxx字符集
GB就是国标的意思,是为了显示中文而设计的一套字符集。
GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
-
Unicode字符集
Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。
它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案:UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
128个US-ASCII字符,只需一个字节编码。
拉丁文等字符,需要二个字节编码。
大部分常用字(含中文),使用三个字节编码。
其他极少使用的Unicode辅助字符,使用四字节编码
乱码举例
-
文本编码与读取编码不一致
IDEA设置,都是默认的UTF-8编码,但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码
/** * @Author charlesYan * @Description //测试乱码情况:源文件采用gbk编码,读取时采用utf-8解码 * @Date 11:11 2020/11/17 * @Param [] * @return void **/ @Test public void testUnintelligible(){ try (FileReader fr = new FileReader("E:\\Blog\\202011171130.txt"); FileInputStream fis = new FileInputStream("E:\\Blog\\202011171130.txt");) { int len; while ((len = fr.read()) != -1) { System.out.println((char) len); } // 定义字节数组 byte[] b = new byte[1024]; // 定义长度 int length; while ((length = fis.read(b)) != -1) { System.out.println(new String(b,0,length)); } } catch (Exception e) { e.printStackTrace(); } }
转换流
InputStreamReader类(字节流->字符流)
-
简介
转换流java.io.InputStreamReader,是Reader的子类,从字面意思可以看出它是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
- 构造方法
InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。 InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
- 使用转换流解决编码问题
/** * @Author charlesYan * @Description //使用转换流读取数据,解决读取乱码问题 * @Date 14:41 2020/11/17 * @Param [] * @return void **/ @Test public void testInputStreamReader(){ // 文件路径内容采用gbk编码,创建流对象指定GBK编码 try(InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\Blog\\202011171112.txt"), "GBK");) { // 定义变量,保存字符 int read; // 使用指定编码字符流读取,正常解析 while ((read = isr.read()) != -1) { System.out.println((char)read); } } catch (Exception e) { e.printStackTrace(); } }
OutputStreamWriter类(字符流->字节流)
-
简介
转换流java.io.OutputStreamWriter ,是Writer的子类,字面看容易混淆会误以为是转为字符流,其实不然,OutputStreamWriter为从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集
- 构造方法
OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。 OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
- 指定编码构造文件
/** * @Author charlesYan * @Description //使用转换流构造指定编码文件 * @Date 14:56 2020/11/17 * @Param [] * @return void **/ @Test public void testOutputStreamWriter() throws Exception { // 此时创建的文件必须以UTF-8格式打开,否则乱码 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\Blog\\202011171500.txt")); String content = "你好";// 保存为6个字节 osw.write(content); osw.close(); // 此时创建的文件必须以GBK格式打开,否则乱码 OutputStreamWriter gbkOsw = new OutputStreamWriter(new FileOutputStream("E:\\Blog\\202011171501.txt"), "GBK"); String substance = "明天";// 保存为4个字节 gbkOsw.write(substance); gbkOsw.close(); }
注意事项
-
提高效率
为了达到最高效率,可以考虑在 BufferedReader 内包装 InputStreamReader
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\Blog\\202011171501.txt")));
- FileReader类仅仅是InputStreamReader的简单衍生并未扩展任何功能
- FileReader类读取数据实质是InputStreamReader类在读取,而InputStreamReader读取数据实际是StreamDecoder类读取,因此在使用字符输入流的时候实际是StreamDecoder类在发挥作用
参考链接
-
史上最骚最全最详细的IO流教程,没有之一!
https://www.cnblogs.com/yichunguo/p/11775270.html
-
JAVA基础知识之InputStreamReader流
https://blog.csdn.net/ai_bao_zi/article/details/81133476