JAVA基础之IO流的学习笔记

image-20210604102220915

IO流基本概念

Java对数据的操作是通过流的方式,IO流用来处理设备之间的数据传输、上传文件和下载文件,Java用于操作流的对象都在IO包中。

IO流分为字节流、字符流和其它流,总来说是五类一接口 其他类基本都是他们的延申:类 File、InputStream、OutputStream、Reader、Writer、RandomAccess和接口Serializable,其中InputStream、OutputStream属于字节流,Reader、Writer属于字符流。区分字节流和字符流可以通过这种方式:如果我们能在自己电脑上用笔记本打开一个文件,那么就可以用字符流去处理它,如果不行就用字节流。因为字符流只能处理文本数据 而字节流可以处理任何类型的文件数据。

字节流

1
2
3
4
基类 InputStream
|__文件操作流 FilterInputStream
|__缓冲流 BufferedInputStream
|__对象流 ObjectInputStream

字节流基础类

InputSream:

InputSream:抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

序号 方法名 解释
1 abstract int read() 从输入流中读取数据的下一个字节
2 int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区 b
3 int read(byte[] b, int off, int len) 从输入流读取最多 len字节的数据到一个字节数组。
4 void close() 关闭此输入流并释放与该流关联的所有系统资源
OutputStream:

OutputStream:抽象类,基于字节的输出操作,是所有输出流的父类。定义了所有输出流都具有的共同特征。

序号 方法名 解释
1 void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流
2 void write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
3 abstract void write(int b) 将指定的字节写入此输出流
4 void close() 关闭此输出流并释放与此流有关的所有系统资源
5 void flush() 刷新此输出流并强制写出所有缓冲的输出字节

字节文件操作流-FileInputStream&FileOutputStream

FileInputStream:字节文件输入流,从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流。

FileOutputStream:字节文件输出流是用于将数据写入到File,从程序中写入到其他位置。

1
2
FileInputStream常用方法:read()、close()
FileOutputStream常用方法:write()、close()

代码示例:

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
public void fileInputStrameTest() throws IOException {
FileInputStream fileInputStream = new FileInputStream("E:\\1.txt");
int by;
//一次读取一个字节
while ((by=fileInputStream.read())!=-1)
{
//因为字符在底层存储的时候就是存储的数值。即字符对应的ASCII码。
//所以需要强制转换一下类型
System.out.print((char)by);
}
//关闭IO流
fileInputStream.close();
}

public void fileOutputStreamTest() throws IOException {
//FileOutputStream(String name, boolean append)如果第二个参数是true ,则字节将写入文件的末尾进行追加。
FileOutputStream fileOutputStream = new FileOutputStream("E:\\2.txt",true);
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextInt()){
int a = scanner.nextInt();
fileOutputStream.write(a);
}
scanner.close();
byte b = 0b1111011;
fileOutputStream.write(b);
fileOutputStream.write('\n');
byte[] c = "123abc".getBytes();
System.out.println(c);
fileOutputStream.write(c);
fileOutputStream.close();

}

字节缓冲流(高效流)-BufferedInputStream&BufferedOutputStream

BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。这两个类分别是FilterInputStreamFilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。

我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!

同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReaderBufferedWriter两个类。

1
2
3
4
5
构造方法:
// 创建一个 BufferedInputStream并保存其参数,即输入流in,以便将来使用。
BufferedInputStream(InputStream in)
// 创建具有指定缓冲区大小的 BufferedInputStream并保存其参数,即输入流in以便将来使用
BufferedInputStream(InputStream in, int size)

BufferedOutputStream:字节缓冲输出流,提高了写出效率。

1
2
3
4
5
6
7
8
9
10
11
12
构造方法:
// 创建一个新的缓冲输出流,以将数据写入指定的底层输出流
BufferedOutputStream(OutputStream out)
// 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
BufferedOutputStream(OutputStream out, int size)
常用方法:
// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流
void write(byte[] b, int off, int len)
// 将指定的字节写入此缓冲的输出流
void write(int b)
// 刷新此缓冲的输出流
void flush()

示例:

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
public void bufferInputStreamTest() throws IOException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("E:\\1.txt"));
//缓冲区大小,代表一次最多读取1KB的内容
byte[] s1=new byte[1024];

int len;
while((len=bufferedInputStream.read(s1))!=-1)
{
System.out.print(new String(s1,0,len));
}
bufferedInputStream.close();
}

public void bufferOutputStreamTest() throws IOException {
OutputStream outputStream = new FileOutputStream("E:\\2.txt");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
bufferedOutputStream.write("好的我明白".getBytes());
bufferedOutputStream.flush();
}

public void bufferTest() throws IOException {
InputStream inputStream = new FileInputStream("E:\\1.txt");
FileOutputStream fileOutputStream = new FileOutputStream("E:\\2.txt");
byte[] buffer = new byte[1024];
int len;
while ((len=inputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,len);
}
inputStream.close();
fileOutputStream.flush();
}

对象流-ObjectInputStream&ObjectOutputStream及序列化

ObjectInputStream 和 ObjectOutputStream 的作用是对基本数据和对象进行序列化操作支持。
Serialization(序列化)是一种将对象转换为字节流的过程;反序列化deserialization是将字节流转换为对象的过程。
一个对象如果想要进行序列化,那么该对象的类必须实现Serializable接口

示例在最后,因为涉及了字符流。

字符流

1
2
3
4
基类 Reader
|__字节转字符 转换流 InputStreamReader
|__文件操作流 FileReader
|__字符缓冲流 BufferReader

字符流基础类-Reader&Writer

Reader:抽象类,基于字节的输入操作,是所有输入字符流的父类。

序号 方法 解释
1 int read() 读取单个字符
2 int read(char[] cbuf) 将字符读入数组
3 abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分
4 long skip(long n) 跳过字符
5 abstract void close() 关闭该流并释放与之关联的所有资源

Writer:抽象类,基于字节的输出操作,是所有输出字符流的父类。

序号 方法 解释
1 void write(char[] cbuf) 写入字符数组
2 abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分
3 void write(int c) 写入单个字符
4 void write(String str) 写入字符串
5 void write(String str, int off, int len) 写入字符串的某一部分
6 abstract void close() 关闭此流,但要先刷新它
7 abstract void flush() 刷新该流的缓冲

字符转换流-InputStreamReader&OutputStreamWriter

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
public void inputStreamReaderTest() throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("E:\\1.txt"));
char[] c = new char[1024];
int len;
while ((len=inputStreamReader.read(c))!=-1){
System.out.println(new String(c,0,len));
}
inputStreamReader.close();
}

public void outputStreamWriterTest() throws IOException {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("E:\\2.txt"),"GBK");
String s = "123发士大夫艰苦";
outputStreamWriter.write(s);
outputStreamWriter.flush();
}

public void test() throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("E:\\1.txt"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("E:\\2.txt"),"GBK");

char[] c = new char[1024];
int len;
while ((len=inputStreamReader.read(c))!=-1){
outputStreamWriter.write(c);
}
inputStreamReader.close();
outputStreamWriter.flush();
}

字符文件操作流-FileReader&FileWriter

FileReader:从InputStreamReader类继承而来。该类按字符读取流中数据。

FileWriter :从 OutputStreamWriter 类继承而来。该类按字符向流中写入数据。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) throws IOException {
FileTest fileTest = new FileTest();
fileTest.fileWriterTest();
fileTest.fileReaderTest("E:\\2.txt");
}

public void fileReaderTest(String filename) throws IOException {
FileReader fileReader = new FileReader(filename);
char[] c = new char[1024];
int len;
while ((len=fileReader.read(c))!=-1){
System.out.println(new String(c,0,len));
}
fileReader.close();
}

public void fileWriterTest() throws IOException {
FileWriter fileWriter = new FileWriter("E:\\2.txt",true);
String s = "123456哈哈哈";
fileWriter.write(s);
fileWriter.flush();
}

字符缓冲流

字符缓冲流 BufferedReader和BufferedWriter跟字节缓冲流类似,只不过一个是字符一个是字节,BufferedReader和BufferedWriter是Reader和Writer的子类。

示例:

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
public class BufferTest {
public static void main(String[] args) throws IOException {
BufferTest bufferTest = new BufferTest();
bufferTest.bufferWriterTest();
bufferTest.bufferReaderTest();
}

public void bufferReaderTest() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("E:\\2.txt"));
String s;
while ((s=bufferedReader.readLine())!=null) {
System.out.println(s);
}
bufferedReader.close();

}

public void bufferWriterTest() throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("E:\\2.txt",true));
bufferedWriter.newLine();
bufferedWriter.write("123123开发了");
bufferedWriter.flush();
bufferedWriter.close();
}
}

对象流示例

示例:序列化一个对象之后,反序列化这个对象,并执行该对象的方法。另外更详细的说明可以看下之前的笔记Java序列化和反序列化

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
38
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Test test = new Test();
test.objectToStreamTest();
test.streamToObjectTest();
}

public void objectToStreamTest() throws IOException {
//对象转字节流
FileOutputStream fileOutputStream = new FileOutputStream("E:\\1.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
Person person = new Person();
objectOutputStream.writeObject(person);
objectOutputStream.close();
}

public void streamToObjectTest() throws IOException, ClassNotFoundException {
//字节流转对象
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\1.txt"));
Person person1 = (Person) objectInputStream.readObject();
person1.run();
}
}

class Person implements Serializable{
public void run() throws IOException {
//获取当前程序环境
Runtime runtime = Runtime.getRuntime();
//执行命令
Process process = runtime.exec(new String[]{"ipconfig","/a"});
//用缓冲区读取执行结果
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
while ((s=bufferedReader.readLine())!=null){
System.out.println(s);
}
}
}

参考链接:

https://www.kuangstudy.com/bbs/1356043480895451137

https://blog.csdn.net/SUN__CGJ/article/details/109467222

https://www.cnblogs.com/zhaoyanjun/p/6376937.html

https://www.cnblogs.com/yuler/p/11990543.html