IO-05-包装流

IO-包装流

根据功能分为节点流和包装流(处理流)

  • 节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader

  • 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据的读写。如BufferedReader,处理流的构造方法总是要带一个其他的流的参数做对象。一个流对象经过其他流的多次包装,称为流的链接。

1. 包装流

  1. 什么是包装流?
  • 包装流隐藏了底层节点流的差异,并对外提供了更方便的输入/输出的功能,让我们只关心这个高级流的操作就好
  • 使用包装流包装了节点流,程序直接操作包装流,而底层还是节点流和IO设备。
  • 关闭包装流的时候,只需要关闭包装流即可。

2. 缓冲流

mark

*缓冲流就是一个包装流,目的是缓存作用,加快读取和写入数据的速度。- *

  • 字符缓冲流:BufferedInputStream、BufferedOutputStream
  • 字节缓冲流:BufferedReader、BufferedWriter

看一个例子:

  • 之前的操作:我们在将字符输入输出流,字节输入输出流的时候。读取/写入操作,通常都会定义一个字节或者字符数组,将读取/写入的数据先存放到这个数组里面,然后在取数组中的数据。这比我们一个一个读取要快很多。这也是缓冲流的由来。

  • 只不过缓冲流定义了一个数组用来存储我们读取/写入的数据

  • 当内部定义的数组满了(注意:我们操作的时候外部还是会定义一个小的数组,小数组放到内部数组中),就会执行下一步的操作

mark

  • 下面是一个没有使用缓冲流的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

public class TestNoBuffer {
public static void main(String[] args) throws IOException {
//1、创建目标对象,输入流表示那个文件的数据保存到程序中。不写盘符,默认该文件是在该项目的根目录下
//a.txt 保存的文件内容为:AAaBCDEF
File target = new File("io"+File.separator+"a.txt");
//2、创建输入流对象
InputStream in = new FileInputStream(target);
//3、具体的 IO 操作(读取 a.txt 文件中的数据到程序中)
/**
* 注意:读取文件中的数据,读到最后没有数据时,返回-1
* int read():读取一个字节,返回读取的字节
* int read(byte[] b):读取多个字节,并保存到数组 b 中,从数组 b 的索引为 0 的位置开始存储,返回读取了几个字节
* int read(byte[] b,int off,int len):读取多个字节,并存储到数组 b 中,从数组b 的索引为 0 的位置开始,长度为len个字节
*/
//int read():读取一个字节,返回读取的字节
int data1 = in.read();//获取 a.txt 文件中的数据的第一个字节
System.out.println((char)data1); //A
//int read(byte[] b):读取多个字节保存到数组b 中
byte[] buffer = new byte[10];//这里我们定义了一个 长度为 10 的字节数组,用来存储读取的数据
in.read(buffer);//获取 a.txt 文件中的前10 个字节,并存储到 buffer 数组中
System.out.println(Arrays.toString(buffer)); //[65, 97, 66, 67, 68, 69, 70, 0, 0, 0]
System.out.println(new String(buffer)); //AaBCDEF[][][]

//int read(byte[] b,int off,int len):读取多个字节,并存储到数组 b 中,从索引 off 开始到 len
in.read(buffer, 0, 3);
System.out.println(Arrays.toString(buffer)); //[65, 97, 66, 0, 0, 0, 0, 0, 0, 0]
System.out.println(new String(buffer)); //AaB[][][][][][][]
//4、关闭流资源
in.close();
}
}
  • 接下来,我们去看缓冲流的JDK底层源码
    • 可以看到,程序中定义了这样的缓存数组,大小是8192
1
2
3
4
public
class BufferedInputStream extends FilterInputStream {

private static int DEFAULT_BUFFER_SIZE = 8192;
  • 最后我们来使用一下
  1. 字节缓冲输入/输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.*;

public class TestBufferedStream {
public static void main(String[] args) throws IOException {
// 字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("io" + File.separator + "a.txt"));

// 定义一个字节数组,用来存储数据
byte[] buffer = new byte[1024];
int len = -1;
while((len=bis.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}

// 关闭资源流
bis.close();

// 字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("io" + File.separator + "a.txt"));
bos.write("ABCD".getBytes());
bos.close();
}
}
  1. 字符缓冲输入/输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;

public class TestBufferedReader {
public static void main(String[] args) throws IOException {
// 字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("io"+ File.separator+"a.txt"));
char[] buffer = new char[10];
int len = -1;
while ((len=br.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
br.close();



// 字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("io" + File.separator + "a.txt"));
bw.write("ABCD");
bw.close();
}
}

3. 转换流

  • 转换流:把字节流转换成字符流
    • InputStreamReader:把字节输入流转换成字符输入流
    • OutputStreamWriter:把字节输出流转换成字符输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.io.*;

// 用转换流进行文件的复制
public class TestConvert {
public static void main(String[] args) throws IOException {
// 1. 创建源和目标
File srcFile = new File("io"+File.separator+"a.txt");
File descFile = new File("io"+File.separator+"b.txt");


// 2. 创建字节输入输出流对象
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(descFile);

// 3. 创建转换输入输出对象
Reader rd = new InputStreamReader(in);
Writer wt = new OutputStreamWriter(out);

// 4. 读取和写入操作
char[] buffer = new char[10]; //创建一个容量为 10 的字符数组,存储已经读取的数据
int len = -1; //表示已经读取了多少个字符,如果是 -1,表示已经读取到文件的末尾
while ((len=rd.read(buffer))!=-1){
wt.write(buffer,0,len);
}

// 5. 关闭流资源
rd.close();
wt.close();

}
}

4. 内存流(数组流)

  • 把数据先临时存在数组中,也就是内存中。
  • 所以这个关闭内存流是无效的,关闭后还能再次调用这个方法。
  • 底层的close()方法是一个空方法。
1
2
3
4
5
6
7
/**
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
*/
public void close() throws IOException {
}

①、字节内存流:ByteArrayOutputStream 、ByteArrayInputStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class TestArrayStream {
public static void main(String[] args) throws IOException {
// 字节数组输出流:程序-》内存
ByteArrayOutputStream bos = new ByteArrayOutputStream();

// 将数据写到内存中
bos.write("ABCD".getBytes());

// 创建一个新分配的字节数组。
// 其大小是当前大小,缓冲区的有效内容已经被复制到其中
byte[] temp = bos.toByteArray();
System.out.println(new String(temp,0,temp.length));


byte[] buffer = new byte[10];
// 字节数组输入流:内存-》程序
ByteArrayInputStream bis = new ByteArrayInputStream(temp);
int len = -1;
while((len=bis.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}

//这里不写也没事,因为源码中的 close()是一个空的方法体
bos.close();
bis.close();
}
}

②、字符内存流:CharArrayReader、CharArrayWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TestArrayReader {
public static void main(String[] args) throws IOException {
// 字符数组输出流
CharArrayWriter caw = new CharArrayWriter();
caw.write("ABCD");

// 返回内存数据的副本
char[] temp = caw.toCharArray();
System.out.println(new String(temp));

// 字符数组输入流
CharArrayReader car = new CharArrayReader(temp);
char[] buffer = new char[10];
int len = -1;
while((len=car.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
}
}

③、字符串流:StringReader,StringWriter(把数据临时存储到字符串中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TestStringReader {
public static void main(String[] args) throws IOException {
// 字符串输出流,底层采用 StringBuffer 进行拼接
StringWriter sw = new StringWriter();
sw.write("ABCD");
sw.write("朱酱酱");
System.out.println(sw.toString());

// 字符串输入流
StringReader sr = new StringReader(sw.toString());
char[] buffer = new char[10];
int len = -1;
while((len=sr.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
}
}

5. 合并流

  • 把多个输入和输出合并成一个流,也叫做顺序流,因为在读取的时候先读取了第一个,读完了再去读取下一个流。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.*;

public class TestSequence {
public static void main(String[] args) throws IOException {
// 定义字节输入合并流
SequenceInputStream seinput = new SequenceInputStream(new FileInputStream("io/a.txt"), new FileInputStream("io/b.txt"));

byte[] buffer = new byte[10];
int len = -1;
while ((len=seinput.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}

seinput.close();
}
}
打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信