javaday24_转换流_缓冲流_流的操作规律

转换流:

为什么有它?

之前的里面的FileWriter  和 FileReader 类的时候,我们知道它们只能采用默认字符编码  和 默认字节缓冲区。

所以我们这里介绍 转换流 它可以指定 字符编码,它能帮助我们解决 往后开发中遇到的乱码问题!

转换流---OutputStreamWriter 类:

文档里说它是 字符流通向字节流 的桥梁。它可以将字符流  转为 字节流。 因为文件的本质其实都是以字节存储的。

注: 

FileOutputStream是 字节流中的输出流 类! (写文件)

FileInputStream 是 字节流中的输入流 类! (读文件)

FileWriter 是 字符流 中的 文件写入方法!(写文件)

FileReader 是 字符流 中的文件读出方法! (读文件)

OutputStreamWriter : 新学的 转换流!它可以将 字符流 转为字节流!  

OutputStreamWriter 的使用:

两个构造函数,

注:编码表 不区分大小写。 

 1 package cn.zcb.demo03;
 2 
 3 import java.io.FileOutputStream;
 4 import java.io.IOException;
 5 import java.io.OutputStreamWriter;
 6 
 7 public class Test {
 8     /*转换流 OutputStreamWriter  的使用*/
 9     public static void main(String[] args) throws IOException {
10         //1,先创建一个  字节输出流(FileOutputStream ),待会 我们的转换流会 连接上它
11         FileOutputStream fileOutputStream = new FileOutputStream("d:\test\a.txt");
12 
13         //2,创建转换流 并连接字节输出流
14         OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"gbk"); //此时也可以省略不写,因为默认就是gbk
15 
16         //3,此时,如果通过转换流写入的 字符就会以转换流指定的编码形式写入到 字节输出流指定的文件中了。
17         outputStreamWriter.write("我爱你中国!");
18 
19         outputStreamWriter.close();//此时,关闭转换流也同样会关闭 字节输出流!
20     }
21 }
写入字符,并且以gbk形式字节保存文件
package cn.zcb.demo03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class Test {
    /*转换流 OutputStreamWriter  的使用*/
    public static void main(String[] args) throws IOException {
        //1,先创建一个  字节输出流(FileOutputStream ),待会 我们的转换流会 连接上它
        FileOutputStream fileOutputStream = new FileOutputStream("d:\test\a.txt");

        //2,创建转换流 并连接字节输出流
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8"); 
        
        //3,此时,如果通过转换流写入的 字符就会以转换流指定的编码形式写入到 字节输出流指定的文件中了。
        outputStreamWriter.write("我爱你中国!");

        outputStreamWriter.close();//此时,关闭转换流也同样会关闭 字节输出流!
    }
}
写入字符,以utf8 形式字节 保存文件

注意:

OutputStreamWriter 有个子类---FileWriter。(也就是我们的字符写入流)。

二者的区别是后者不能更改编码表,只能使用默认的编码表来转换为字节;前者可以更改编码表!

转换流---OutputStreamReader 类:

它可以将字节流  转为字符流。  

和 写入的时候一样,我们前面使用的读字符的类 FileReader 只能用于 默认编码。如果我们想使用其他编码来读文件。就要使用FileReader的父类OutputStreamReader的帮助了。 

它类似于上面介绍的过程,它是先通过FileInputStream字节输入流 从文件中读入得到 相应的字节。 然后,它在通过制定的编码表 将字节转换为 字符输出! 

它的构造函数,此时是多态!

 1 package cn.zcb.demo03;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 
 8 public class Test {
 9     /*转换流 OutputStreamWriter  的使用*/
10     public static void main(String[] args) throws IOException {
11         //1,先创建一个 字节输入流 ,从文件中读取相应的字节 出来, 待会我们的InputStreamReader会连接它。
12         FileInputStream fileInputStream = new FileInputStream("d:\test\a(gbk 编码).txt");
13 
14         //2,创建转换流 InputStreamReader ,并连接 我们的字节输入流
15         InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"gbk"); //gbk可以省略
16 
17         //3,此时,如果读取文件,就会以 转换流指定的编码  将文件中的字节   读取到程序中了。
18         char[] arr = new char[1024];
19         int ret = inputStreamReader.read(arr);  //因为我们知道一次一定可以读完,所以没有循环读取,如果不确定是否能读完,要进行循环读取
20         System.out.println(arr);
21 
22         inputStreamReader.close(); //同时,用于连接的 字节输入流 也会被关闭
23     }
24 }
从文件中读出 字节,然后 通过查询 gbk编码表 转换为字符输出!
 1 package cn.zcb.demo03;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 import java.io.InputStreamReader;
 6 
 7 public class Test {
 8 
 9     /*转换流 OutputStreamWriter  的使用*/
10     public static void main(String[] args) throws IOException {
11         //1,先创建一个 字节输入流 ,从文件中读取相应的字节 出来, 待会我们的InputStreamReader会连接它。
12         FileInputStream fileInputStream = new FileInputStream("d:\test\a(utf8 编码).txt");
13 
14         //2,创建转换流 InputStreamReader ,并连接 我们的字节输入流
15         InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf8"); //gbk可以省略
16 
17         //3,此时,如果读取文件,就会以 转换流指定的编码  将文件中的字节   读取到程序中了。
18         char[] arr = new char[1024];
19         int ret = inputStreamReader.read(arr);  //因为我们知道一次一定可以读完,所以没有循环读取,如果不确定是否能读完,要进行循环读取
20         System.out.println(arr);
21 
22         inputStreamReader.close(); //同时,用于连接的 字节输入流 也会被关闭
23     }
24 }
从文件中读出 字节,然后 通过查询 utf8编码表 转换为字符输出

转换流  的子类 父类的区别:

转换流  OutputStreamWriter 和 InputStreamReader 两个可以指定编码表; 

它们的子类 FileWriter  和 FileReader 两个只能是默认的编码表。 

缓冲流:

在流对象中,效率是个头疼的事情,我们上次的时候使用数组 提高了效率(不至于一次读一个,一次读一个数组 )。

其实,系统中已经提供好了一套缓冲流,它们设计的目的就是为了提高IO操作速度。 

缓冲流都是以 Buffered开头。

四大缓冲流!

字节缓冲流:

BufferedOutputStream 字节缓冲 输出流

它继承自OutputStream ,也是字节输出流。 起到缓冲作用。

 1 package cn.zcb.demo03;
 2 
 3 
 4 import java.io.BufferedOutputStream;
 5 import java.io.FileOutputStream;
 6 import java.io.IOException;
 7 
 8 public class Test {
 9     /*字节缓冲输出流的  的使用*/
10     public static void main(String[] args) throws IOException {
11         //1, 创建一个 字节输出流
12         FileOutputStream fileOutputStream = new FileOutputStream("d:\test\c.txt");
13         //2,创建一个字节缓冲输出流 它 可以提高 字节输出流写入文件的效率!
14         BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
15 
16         //3,使用字节缓冲输出流 提高字节输出流的 效率。 
17         bufferedOutputStream.write("Hello 我爱你呀".getBytes());
18 
19         //4,关闭
20         bufferedOutputStream.close(); //此时的 缓冲流也会被关闭 !
21     }
22 }
使用字节缓冲输出流 提高字节输出流的 效率

BufferedInputStream字节缓冲 输入流 

 1 package cn.zcb.demo03;
 2 
 3 
 4 import java.io.BufferedInputStream;
 5 import java.io.FileInputStream;
 6 import java.io.IOException;
 7 
 8 public class Test {
 9     /*字节缓冲输出流的  的使用*/
10     public static void main(String[] args) throws IOException {
11         //1, 创建一个 字节输入流
12         FileInputStream fileInputStream = new FileInputStream("d:\test\c.txt");
13         //2,创建一个字节缓冲输入流 它 可以提高 字节输入流 读取文件的效率!
14         BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); //里面是被提高效率的流。
15 
16         //3,使用buffer 提高 效率。
17         byte[] b = new byte[1024];
18         bufferedInputStream.read(b);  //这里我们知道一次可以读完!
19         System.out.println(new String(b));
20 
21         //4,关闭
22         bufferedInputStream.close(); //此时的 缓冲流也会被关闭 !
23     }
24 
25 }
使用字节缓冲输入流  提高字节输入流的效率 
 1 package cn.zcb.demo03;
 2 
 3 
 4 public class Test {
 5 
 6     public static void main(String[] args) {
 7         //我们一直使用的 System.in  我们发现 它是抽象类 InputStream 的子类的对象 。其实这个子类就是BufferedInputStream 类
 8         //证明如下:
 9         System.out.println(System.in); //java.io.BufferedInputStream@2d98a335
10         //所以,我们在键盘输入的时候,传入 System.in 也是为了提高,字节输入流的效率的。
11     }
12 }
System.in 其实就是BufferedInputStream 的对象,它就是通过字节缓冲 输入流 来提高 System.in的效率的!

四种文件复制 效率比较:

 1 package cn.zcb.demo03;
 2 
 3 import java.io.*;
 4 import java.util.Arrays;
 5 
 6 public class Test {
 7     public static void main(String[] args) throws IOException{
 8         long begin_time = System.currentTimeMillis(); //毫秒值!
 9         function01(new File("d:\a.txt"),new File("e:\a.txt")); //文件大小为 2Mb
10         long end_time1 = System.currentTimeMillis();
11         System.out.println(end_time1 - begin_time);  //11388ms
12 
13         function02(new File("d:\a.txt"),new File("e:\a.txt")); //文件大小为 2Mb
14         long end_time2 = System.currentTimeMillis();
15         System.out.println(end_time2 - end_time1); //31ms
16 
17         function03(new File("d:\a.txt"),new File("e:\a.txt")); //文件大小为 2Mb
18         long end_time3 = System.currentTimeMillis();
19         System.out.println(end_time3 - end_time2); //32ms
20 
21         function04(new File("d:\a.txt"),new File("e:\a.txt")); //文件大小为 2Mb
22         long end_time4 = System.currentTimeMillis();
23         System.out.println(end_time4 - end_time3); //15ms
24 
25     }
26     public static void function01(File src,File dest) throws IOException {
27         /*第一种 字节流读写 单个字节*/
28         FileInputStream fileInputStream = new FileInputStream(src); //读入
29         FileOutputStream fileOutputStream  = new FileOutputStream(dest); //写出
30         int ret;
31         while ((ret = fileInputStream.read()) != -1){
32             fileOutputStream.write(ret);
33         }
34         fileInputStream.close();
35         fileOutputStream.close();
36     }
37     public static void function02(File src,File dest) throws IOException{
38         /*第二种 字节流读写 字节数组*/
39         FileInputStream fileInputStream = new FileInputStream(src); //读入
40         FileOutputStream fileOutputStream  = new FileOutputStream(dest); //写出
41         int ret;
42         byte[] arr = new byte[1024];
43         while ((ret = fileInputStream.read(arr)) != -1){
44             fileOutputStream.write(arr);
45             //清空 arr
46             Arrays.fill(arr,(byte)0);
47         }
48         fileInputStream.close();
49         fileOutputStream.close();
50     }
51     public static void function03(File src,File dest) throws IOException{
52         /*第三种 字节缓冲流读写 单个字节 */
53         FileInputStream fileInputStream = new FileInputStream(src);
54         FileOutputStream fileOutputStream  = new FileOutputStream(dest);
55         BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);  //读入
56         BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);  //写出
57 
58         int ret;
59         while ((ret = bufferedInputStream.read()) != -1){
60             bufferedOutputStream.write(ret);
61         }
62         bufferedInputStream.close();
63         bufferedOutputStream.close();
64 
65     }
66     public static void function04(File src,File dest) throws IOException{
67         /*第四种 字节缓冲流读写 字节数组 */
68         FileInputStream fileInputStream = new FileInputStream(src); //读入
69         FileOutputStream fileOutputStream  = new FileOutputStream(dest); //写出
70         BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);  //读入
71         BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);  //写出
72 
73         int ret;
74         byte[] arr = new byte[1024];
75         while ((ret = bufferedInputStream.read(arr)) != -1){
76             bufferedOutputStream.write(arr);
77             //清空 arr
78             Arrays.fill(arr,(byte)0);
79         }
80         bufferedInputStream.close();
81         bufferedOutputStream.close();
82     }
83 
84 
85 }
86 /*输出:
87 11388
88 31
89 32
90 15
91 * */
View Code

所以,结果很明显,推荐使用缓冲流来 进行IO操作! 

字符缓冲流:

完成文本数据的高效的写入 与 读取的操作。 

BufferedWriter 字符缓冲输出流

 1 package cn.zcb.demo03;
 2 
 3 import java.io.BufferedWriter;
 4 import java.io.FileWriter;
 5 import java.io.IOException;
 6 
 7 public class Test {
 8     /*字符缓冲输出流 的使用*/
 9     public static void main(String[] args) throws IOException {
10         FileWriter fileWriter = new FileWriter("d:\d.txt");
11         BufferedWriter bufferedWriter =new BufferedWriter(fileWriter); //使用buffered 提高了 fileWriter流的效率
12 
13         bufferedWriter.write(97); //写字符 a
14         bufferedWriter.write("hello world".toCharArray());//写字符数组
15         bufferedWriter.write("我爱你中国!"); //写字符串
16 
17         bufferedWriter.close();//此时,fileWriter也跟着 被关闭了 。
18     }
19 }
20 /*输出:
21 * */
使用BufferedWriter 字符缓冲输出流 提高 字符输出流的效率!

不过,这个BufferedWriter字符缓冲输出流,它具有一个自己特有的方法:void newLine()  .它的意思是写换行。  

我们之前换行是使用 ,

这个方法直接就是换行,而且关键的是它与平台无关。所以,建议使用newLine()  方法。 

 1 package cn.zcb.demo03;
 2 
 3 import java.io.BufferedWriter;
 4 import java.io.FileWriter;
 5 import java.io.IOException;
 6 
 7 public class Test {
 8     /*字符缓冲输出流 的使用*/
 9     public static void main(String[] args) throws IOException {
10         FileWriter fileWriter = new FileWriter("d:\d.txt");
11         BufferedWriter bufferedWriter =new BufferedWriter(fileWriter); //使用buffered 提高了 fileWriter流的效率
12 
13         bufferedWriter.write(97); //写字符 a
14         bufferedWriter.newLine();
15         bufferedWriter.write("hello world".toCharArray());//写字符数组
16         bufferedWriter.newLine();
17         bufferedWriter.write("我爱你中国!"); //写字符串
18 
19         bufferedWriter.close();//此时,fileWriter也跟着 被关闭了 。
20     }
21 }
22 /*输出:
23 * */
.newLine() 的使用!

BufferedReader 字符缓冲输入流  

对于 读取一个字符  和  读取 字符数组,这里不说了。 

它也有自己的一个特殊方法,就是可以一下读一个整行,并返回一个字符串。 String readLine();  它依靠的是  当遇到终止符(   ),停止读取;返回的字符串中不包含终止符。

如果读到文件末尾,返回null 。 

 1 package cn.zcb.demo03;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.FileReader;
 5 import java.io.IOException;
 6 
 7 public class Test {
 8     /*字符缓冲输入流 的使用*/
 9     public static void main(String[] args) throws IOException {
10         FileReader fileReader = new FileReader("d:\d.txt");
11 
12         //创建字符缓冲输入流 BufferedReader
13         BufferedReader bufferedReader = new BufferedReader(fileReader);
14 
15 //      1,  bufferedReader.read(); //读到 一个字符
16 //      2,  bufferedReader.read(arr); //读到 一个字符数组中
17 
18 //      3,   BufferedReader 的特有方法: readLine();  读取行。
19 //        String ret =  bufferedReader.readLine();
20 //        System.out.println(ret);
21         //循环 行读取
22         String ret;
23         while ((ret = bufferedReader.readLine()) != null){
24             System.out.println(ret); //ret 为读取到 行 ,它是个字符串,而且它里面没有 任何终止符 存在!
25         }
26 
27     }
28 }
29 /*输出:
30 * */
BufferedReader 字符缓冲输入流 的特有方法String readLine() 方法, 

补充:

 

注: BufferedReader 有个已知子类 LineNumberReader 它可以帮我们读取的内容实现 带有行号。 其实行号就是个计数器,我们也可以自己手动实现。  

 1 package cn.zcb.demo03;
 2 
 3 import java.io.FileReader;
 4 import java.io.IOException;
 5 import java.io.LineNumberReader;
 6 
 7 public class Test {
 8     /*字符缓冲输入流BufferedReader 的子类 LineNumberReader(带有行号) 的使用*/
 9     public static void main(String[] args) throws IOException {
10         FileReader fileReader = new FileReader("d:\d.txt");
11         LineNumberReader lineNumberReader = new LineNumberReader(fileReader );
12 
13         lineNumberReader.getLineNumber();
14         String ret;
15         while ((ret = lineNumberReader.readLine()) != null){
16             System.out.println(lineNumberReader.getLineNumber()+" "+ret);
17         }
18     }
19 }
20 /*输出:
21 1 a
22 2 hello world
23 3 我爱你中国!
24 * */
View Code

但是,其实我们用一个变量做计数器就能实现这个功能。 

字符缓冲流 复制文本文件:

 1 package cn.zcb.demo03;
 2 
 3 import java.io.*;
 4 
 5 public class Test {
 6     /*字符缓冲流  复制文件*/
 7     public static void main(String[] args) throws IOException {
 8         BufferedReader bufferedReader = new BufferedReader(new FileReader("d:\d.txt"));
 9         BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("e:\e.txt"));
10 
11         //循环 读取文本行,写文本行,最后再写换行。
12         String ret;
13         while ((ret = bufferedReader.readLine()) != null){
14             bufferedWriter.write(ret); //写文本行。
15             bufferedWriter.newLine();  //写 换行(因为读取到的是没有 终止符的)
16         }
17 
18         bufferedReader.close();
19         bufferedWriter.close();
20     }
21 }
22 /*输出:
23 1 a
24 2 hello world
25 3 我爱你中国!
26 * */
View Code

但是,此时的问题是 复制后的文件会多两个字节。原因是多复制了一个空行。

多了个空行对于文本文件来说,不算什么,

但是对于图片,视频等文件来说,可能就打不开了。 这是个问题!

流 的操作规律:

IO 流的 四大抽象 基类:

1, InputStream   2,   Reader 

3,OutputStream 4,   Writer  

所有的流都是它们的孩子。 

四个明确:

1,明确操作的是读取文件(1,2基类),还是写入文件(3,4基类)。

2,明确操作的数据 是 字节还是字符。 字节(非文本)用(1,3基类),字符(文本文件)用(2,4基类)。 

3,明确数据所在的具体设备

源设备: 

硬盘上文件, File开头的流。

内存里数组,字符串,需要用到内存流,例如ByteArrayInputStream,等等,这里是从内存中读取数据,或写入到内存中。 

键盘:System.in  流。 

网络:Socket 流 

目的设备: 

硬盘上文件,File开头的 流 

内存,数组,字符串,例如ByteArrayOutputStream

屏幕:System.out 流。 

网络 :Socket 流。

4,明确是否需要额外功能,额外功能指

需要进行转换吗?转换流。 InputStreamReader 和 OutputStreamWriter。

需要提高 效率吗?  缓冲流 。BufferedXXX.  

IO流的继承图:

操作字节的流:


InputStream  <-- FileInputStream(操作文件的字节输入流)   <--BufferedInputStream(提高 字节输入流的效率)

OutputStream  <--FileOutputStream(操作文件的字节输出流) <--BufferedOutputStream(提高 字节输出流的效率)

操作字符的流:

Writer   <--  OutputStreamWriter(可以指定编码表) <--FileWriter(简便的 字符输出流)   

     <--  BufferedWriter(提高 字符输出流的 效率)

Reader <-- InputStreamReader (可以指定编码表)  <--FileReader(简便的 字符输入流)  

             <--  BufferedReader(提高 字符输入流的 效率)

原文地址:https://www.cnblogs.com/zach0812/p/11958472.html