Java IO之字符流

Java IO之字符流

1、字符集与字符编码

  • 为何要有字符集

  咱们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。那 么在这二者之间的转换规则就须要一个统一的标准,不然就会出现乱码了现象;小伙伴QQ上传过来的文件,在咱们本地打开又乱码了。 因而为了实现转换标准,各类字符集标准就出现了。html

  • 什么是字符集

  简单的说字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值表明了哪一个文字(解 码)的转换关系。java

  • 什么是字符编码

  计算机只能存储0,1之类2进制数字,怎么样让它表示那么多各类各样的字符呢?就须要对各类字符指定一个数值的编码代号,这就是字符编码。如:a这个字符,在ascii字符集编码表中对应的编号是97,而“中”在gb2312字符集中对应的编号是:16进制是D6D0 10进制是54992 。经过编号就能够找到计算机对应字符。不用将那么复杂的字符保存在计算机中,只须要保存它代号就好。字符集只是指定了一个集合中有哪些字符,而字符编码,是为这个集合中全部字符定义个编号,这就是字符集与编码区别所在。编程

  此外计算机中只保存字符在某字符集中对应的字符编号值,计算机只须要维持一份字符集清单,当读到这种编号值(编码),就在对应字符清单中找出该字符显示出来便可。字符大小颜色都是程序按照字符样式绘制而成的。如图:数组

  计算机并不区分二进制文件与文本文件。全部的文件都是以二进制形式来存储的,所以,从本质上说,全部的文件都是二进制文件。因此字符流是创建在字节流之上的,它可以提供字符层次的编码和解码。列如,在写入一个字符时,Java虚拟机会将字符转为文件指定的编码(默认是系统默认编码),在读取字符时,再将文件指定的编码转化为字符。app

  常见的码表以下:编程语言

  ASCII:美国标准信息交换码。用一个字节的7位能够表示。ide

  ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1(拉丁编码)或“西欧语言”。ASCII码是包含的仅仅是英文字母,而且没有彻底占满256个编码位置,因此它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号藉以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。于是它依然是一个单字节编码,只是比ASCII更全面。测试

  GB2312:英文占一个字节,中文占两个字节.中国的中文编码表。ui

  GBK:中国的中文编码表升级,融合了更多的中文文字符号。编码

  Unicode: 国际标准码规范,融合了多种文字。全部文字都用两个字节来表示,Java语言使用的就是unicode。

  UTF-8:最多用三个字节来表示一个字符。

  咱们之后接触最多的是iso8859-一、gbk、utf-8

  查看上述码表后,很显然中文的‘中’在iso8859-1中是没有对映的编码的。或者一个字符在2中码表中对应的编码不一样,例若有一些字在不一样的编码中是有交集的,例如bjg5 和gbk 中的汉字简体和繁体多是同样的,就是有交集,可是在各自码表中的数字不同。

  例如使用gbk 将中文保存在计算机中,中国对应gbk编码为100  200若是使用big5 打开,可能   ?  ...  不一样的编码对映的是不同的。很显然,咱们使用什么样的编码写数据,就须要使用什么样的编码来读数据。

  ISO8859-1:一个字节

  GBK: 两个字节包含了英文字符和扩展的中文   ISO8859-1+中文字符

  UTF-8 万国码,推行的。是1~3个字节不等长。英文存的是1个字节,中文存的是3个字节,是为了节省空间。

  • 乱码

  若是一个字符按照一个字符集存储在计算机中(编码),而使用另外一种字符集读取该字符(解码)那就会出现乱码现象。应为计算机中存储使用的字码表与读取使用的字码表不匹配。

2、java中字符的编码与解码

  计算机中存储和传输的基本单位是字节,而咱们看到的信息是字符(人能看懂的)。

  编码:编码就是真实字符与二进制串的对应关系,真实字符转换成二进制串。编码是信息从一种形式或格式转换为另外一种形式的过程也称为计算机编程语言的代码简称编码。用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。

  java中的编码:

  在byte[] buffer=string.getBytes();中,若是没有给.getBytes();指定字符集,那么在编码过程当中,就会按照系统默认的编码格式进行编码。

String str="中"; byte [] b_gbk=str.getBytes("GBK"); byte [] b_utf=str.getBytes("UTF-8"); byte [] b_unic=str.getBytes("UTF-16"); byte [] b_Iso=str.getBytes("ISO8859-1");

  解码:解码就是二进制串与真实字符的对应关系,二进制串转换成真实字符。将信息从已经编码的形式恢复到编码前原状的过程。也就是用特定方法把数码还原成它所表明的内容或将电脉冲信号、光信号、无线电波等转换成它所表明的信息、数据等的过程。

  java中的解码:

 //str按照 GBK编码 后 ,再按照GBK解码 String str_1=new String(str.getBytes("GBK"), "GBK"); String str_2=new String(str.getBytes("UTF-8"), "UTF-8"); String str_3=new String(str.getBytes("UTF-32"), "UTF-32"); String str_4=new String(str.getBytes("ISO8859-1"), "ISO8859-1");

3、关于字符流的一些探讨:

  字符流为什么存在

  既然字节流提供了可以处理任何类型的输入/输出操做的功能,那为何还要存在字符流呢?容我慢慢道来,字节流不能直接操做Unicode字符,由于一个字符有两个字节,字节流一次只能操做一个字节。若是JAVA不能直接操做字符,我会感到JAVA对这个世界满满的恶意,因此提供对直接的字符输入/输出的支持是颇有必要的,由于咱们的口号是:一次编写,处处运行。

  字符流的概念

  输出字符流:把要写入文件的字符序列(实际是unicode码元序列)转为指定编码方式下的字节序列,而后在写入文件中。

  输入字符流:把要读取的字节序列按照指定编码方式转为相应的字符序列(实际是unicode码元序列),从而写入内存中。

  字符流的层次关系

  字符流层次结构的顶层是Reader和Writer抽象类,与字节流中的InputStream、OutputStream相对应。经常使用类继承结构图以下:

4、字符流

  字符流处理的单元为2个字节的Unicode字符,分别操做字符、字符数组或字符串。字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的。字符流操做的是缓冲区(当咱们对文件进行读写操做时若是不调用close() 或 flush()方法时不能看到数据的变化)。

  java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码),文件是byte byte byte ...的数据序列,文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果
  字符流(Reader Writer)---->操做的是文本文本文件,字符的处理,一次处理一个字符,字符的底层任然是基本的字节序列

(一)、字符输入流

  将磁盘(文件)中的数据读入内存中

  Reader 是全部的输入字符流的父类,它是一个抽象类。

  InputStreamReader:将字节输入流转换为字符输入流。是字节流通向字符流的桥梁,能够指定字节流转换为字符流的字符集。完成byte流解析为char流,按照编码解析

  FileReader:该类从InputStreamReader类继承而来,能够关联源文件,是字符流的过滤器

  BufferedReader(缓冲流):字节输入缓冲流,一次只能读一行,从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。BufferedReader 由Reader类扩展而来,提供通用的缓冲方式文本读取,并且提供了很实用的readLine。

  LineNumberReader(关于行号缓冲流):它是BufferedReader的子类,LineNumberReader比BufferedReader多了个功能,就是能够获取当前行号getLineNumber()与设置起始行号setLineNumber(int lineNumber)。默认状况下,行编号从 0 开始。该行号随数据读取在每一个行结束符处递增,而且能够经过调用 setLineNumber(int) 更改行号。但要注意是,setLineNumber(int) 不会实际更改流中的当前位置;它只更改将由 getLineNumber() 返回的值。

(二)、字符输出流

  将内存中的数据按照字符形式写入磁盘(文件)中

  Writer:是全部的输出字符流的父类,它是一个抽象类。

  OutputStreamWriter:将字节输出流转为字符输出流,是字符流通向字节流的桥梁,可以使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集能够由名称指定或显式给定,不然将接受平台默认的字符集。即OutputStreamWriter提供char流到byte流,按照编码处理

  FileWriter:类从OutputStreamWriter类继承而来。该类按字符向流中写入数据,能够关联源文件,是字符流的过滤器

  BufferedWriter(缓冲流):字节输出缓冲流,将文本写入字符输出流,一次只能写一行,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 能够指定缓冲区的大小,或者接受默认的大小。在大多数状况下,默认值就足够大了。 该类提供了 newLine() 方法,它使用平台本身的行分隔符概念,此概念由系统属性 line.separator 定义。该类写入文本的方法就是父类Writer提供的write()系列方法,在后面的示例中我么将演示他特有的newLine( )方法。

5、示例分析

(一)、InputStreamReader和OutStreamWriter示例

 1 package me.io.chars;  2 
 3 import java.io.FileInputStream;  4 import java.io.FileOutputStream;  5 import java.io.IOException;  6 import java.io.InputStreamReader;  7 import java.io.OutputStreamWriter;  8 
 9 /**
10  * InputStreamReader和OutStreamWriter示例 11  * 12  * @author Administrator 13  * 14  */
15 public class IsrAndOswDemo { 16     public static void main(String[] args) throws IOException { 17     String file = "src/me/io/IOUtils.java"; 18     //默认项目的编码,未来操做时要写文件自己的编码格式,否则会乱码
19     InputStreamReader isr = new InputStreamReader(new FileInputStream(file)); 20     OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test.java"), "UTF-8"); 21     /*
22  int num = 0; 23  while((num = isr.read()) != -1) { 24  System.out.print((char)num); 25  }*/
26     int c = 0; 27     char[] buf = new char[8*1024]; 28     StringBuilder sb = new StringBuilder(); 29     /**
30  * 批量读取,放入到buf这个字符数组,从第零个位置开始放,最多放buf.length个 31  * 返回的是读取到的字符个数 32      */
33     while((c = isr.read(buf, 0, buf.length)) != -1) { 34         sb.append(buf, 0, c); 35         osw.write(buf, 0, c); 36  osw.flush(); 37  } 38  System.out.print(sb); 39  isr.close(); 40  osw.close(); 41  } 42 }
IsrAndOswDemo

(二)、FileReader和FileWriter示例

 1 package me.io.chars;  2 
 3 import java.io.FileReader;  4 import java.io.FileWriter;  5 import java.io.IOException;  6 
 7 /**
 8  * FileReader和FileWriter测试类  9  * @author Administrator 10  * 11  */
12 public class FrAndFwDemo { 13     public static void main(String[] args) throws IOException { 14 
15     FileReader fr = new FileReader("src/me/io/IOUtils.java"); 16     //参数true表明能够追加内容
17     FileWriter fw = new FileWriter("demo/test.java", true); 18     char[] buf = new char[8*1024]; 19     int c = 0; 20     while((c = fr.read(buf, 0, buf.length)) != -1) { 21         fw.write(buf, 0, c); 22  fw.flush(); 23  } 24  fr.close(); 25  fw.close(); 26  } 27 }
FrAndFwDemo

(三)、BufferedReader,BufferedWriter,PrintWriter示例

 1 package me.io.chars;  2 
 3 import java.io.BufferedReader;  4 import java.io.BufferedWriter;  5 import java.io.FileInputStream;  6 import java.io.FileOutputStream;  7 import java.io.IOException;  8 import java.io.InputStreamReader;  9 import java.io.OutputStreamWriter; 10 import java.io.PrintWriter; 11 
12 /**
13  * 过滤流 14  * BufferedReader,BufferedWriter,PrintWriter示例 15  * @author Administrator 16  * 17  */
18 public class BrAndBwOrPwDemo { 19 
20     public static void main(String[] args) throws IOException { 21     BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("src/me/io/IOUtils.java"))); 22     //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("demo/test.java")));
23     PrintWriter pw = new PrintWriter("demo/test.java"); 24     String line = null; 25     while((line = br.readLine()) != null) { 26         //不能读取换行
27  System.out.println(line); 28 // bw.write(line); 29 //        //单独写出换行操做 30 // bw.newLine(); 31 // bw.flush();
32  pw.println(line); 33  pw.flush(); 34  } 35  br.close(); 36     //bw.close();
37  pw.close(); 38  } 39 }
BrAndBwOrPwDemo

 

 参考文章:

  https://www.cnblogs.com/jalja/p/6030137.html

  https://yq.aliyun.com/articles/33685

  https://www.cnblogs.com/dongguacai/p/5676254.html

相关文章
相关标签/搜索