第七章 输入输出流
第二节 输入输出流详解与应用
概述
本节内容围绕Java语言中的输入输出流(IO流)展开,详细讲解Java IO的基本概念、分类、工作原理及其常用类的使用方法。输入输出流是Java程序与外部设备(如文件、键盘、网络等)进行数据交换的重要工具,掌握其原理和应用对于二级考试以及实际开发都至关重要。
学习本节后,考生将能够:
- 理解Java输入输出流体系结构和分类
- 熟练使用常见的字节流与字符流类进行文件读写操作
- 掌握缓冲流的优势及用法,提升IO性能
- 理解数据流的应用,处理基本数据类型的输入输出
- 解决实际开发中的IO问题,避免常见误区
核心概念
- 输入流(InputStream):用于读取数据的流,数据从外部设备流向程序。
- 输出流(OutputStream):用于写出数据的流,数据从程序流向外部设备。
- 字节流(Byte Stream):以字节为单位处理数据的流,适用于所有类型文件。
- 字符流(Character Stream):以字符为单位处理数据的流,专门处理文本数据,自动处理编码转换。
- 缓冲流(Buffered Stream):在基本流的基础上提供缓冲机制,减少IO次数,提高效率。
- 数据流(Data Stream):可读写Java基本数据类型的流,方便处理二进制数据。
- 文件流(File Stream):用于读写文件的流,提供文件级别的IO操作。
原理分析
Java IO基于流的模型设计,即数据以流的形式在程序和外部设备之间传递。流有输入流和输出流两种方向,分类上分为字节流和字符流。
- 字节流以8位字节为单位,适合所有文件类型,包括二进制文件。
- 字符流以16位字符为单位,适合文本文件,自动完成字符编码和解码。
缓冲流通过在内存中开辟缓冲区,减少每次读写操作的系统调用次数,极大提升性能。
数据流基于字节流,实现对Java基本数据类型的高效读写,避免手动转换。
Java IO设计遵循“装饰者模式”,即流可以通过层层包装,扩展功能。例如:
- FileInputStream -> BufferedInputStream -> DataInputStream
这种机制既保证了灵活性,又增强了扩展性。
详细内容
1. 字节流详解
Java提供了InputStream和OutputStream两个抽象基类,所有字节流类均继承自它们。常用子类包括:
- FileInputStream / FileOutputStream:用于文件读写
- ByteArrayInputStream / ByteArrayOutputStream:用于内存中的字节数组读写
- FilterInputStream / FilterOutputStream:用于包装其他流,增加功能
字节流读取文件示例:
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:read()方法返回的是字节的整数形式,-1表示文件末尾。
2. 字符流详解
字符流基类为Reader和Writer,常用子类包括:
- FileReader / FileWriter:文件字符读写
- BufferedReader / BufferedWriter:带缓冲的字符读写,支持按行读取
- InputStreamReader / OutputStreamWriter:桥接字节流和字符流
字符流读取文件示例(按行读取):
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("test.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
重点:字符流自动处理编码,推荐用于文本文件操作。
3. 缓冲流详解
缓冲流通过内部缓冲区减少磁盘IO次数,提高读写效率。常用类有:
- BufferedInputStream / BufferedOutputStream(字节缓冲流)
- BufferedReader / BufferedWriter(字符缓冲流)
使用缓冲流一般需要包装基本流,如:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));
缓冲流适合大文件读写,提升性能显著。
4. 数据流详解
数据流DataInputStream和DataOutputStream可读写基本数据类型,方便进行二进制数据处理。
示例:写入和读取基本类型
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"));
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeUTF("Hello");
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"));
int i = dis.readInt();
double d = dis.readDouble();
String s = dis.readUTF();
dis.close();
System.out.println(i + ", " + d + ", " + s);
数据流保证写入顺序与读取顺序一致,否则会出现数据错乱。
5. 文件流操作总结
文件流是操作文件的基础,结合缓冲流和数据流可以完成高效且多样的文件操作。常用步骤:
- 创建文件流对象
- 根据需要包装缓冲流或数据流
- 调用读写方法处理数据
- 关闭流释放资源
实例分析
案例一:文本文件复制
背景:将一个文本文件内容复制到另一个文件。
分析:文本文件应使用字符流,推荐使用缓冲字符流按行读取与写入。
BufferedReader br = new BufferedReader(new FileReader("input.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
结论:使用缓冲字符流按行处理,代码简洁且效率较高。
案例二:二进制文件复制(图片)
背景:复制一个图片文件。
分析:图片为二进制文件,需要使用字节流。为提高效率,添加缓冲流。
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("dest.jpg"));
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bis.close();
bos.close();
结论:缓冲字节流提升大量数据读写性能,适合二进制文件。
案例三:利用数据流存储与读取学生信息
背景:将学生信息(学号int,姓名String,成绩double)写入文件,并读取。
分析:使用DataOutputStream和DataInputStream,方便写入和读取多种数据类型。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("student.dat"));
dos.writeInt(1001);
dos.writeUTF("张三");
dos.writeDouble(88.5);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("student.dat"));
int id = dis.readInt();
String name = dis.readUTF();
double score = dis.readDouble();
dis.close();
System.out.printf("学号:%d, 姓名:%s, 成绩:%.2f", id, name, score);
结论:数据流方便处理多样化数据,适合结构化信息的文件存储。
常见误区
误区:字符流可以处理所有文件类型
- 纠正:字符流只适合文本文件,二进制文件必须使用字节流。
误区:关闭流时只关闭外层流即可
- 纠正:关闭包装流时会自动关闭内层流,无需重复关闭。
误区:不使用缓冲流导致程序效率低下
- 纠正:缓冲流极大提升IO效率,推荐大文件操作时使用。
误区:数据流读写顺序不对应
- 纠正:数据流读写必须严格对应,顺序错乱会导致读取异常。
误区:不捕获或处理IO异常
- 纠正:IO操作易出现异常,必须使用try-catch-finally或try-with-resources确保资源释放。
应用场景
- 文件读写:文本日志文件的生成与读取,配置文件的操作。
- 网络通信:通过流传输数据,实现客户端与服务器的数据交换。
- 多媒体处理:图片、音频、视频文件的复制与处理。
- 数据存储:使用数据流保存和读取结构化数据,如用户信息、游戏存档。
- 缓冲优化:大文件传输时利用缓冲流提升效率,减少资源消耗。
知识拓展
- NIO(New IO)简介:Java NIO是Java 1.4引入的新IO库,支持非阻塞IO、缓冲区管理、多路复用等,适合高效数据处理。
- 字符编码问题:InputStreamReader和OutputStreamWriter支持指定字符编码,避免乱码。
- 序列化流:ObjectInputStream和ObjectOutputStream支持对象的序列化和反序列化,实现对象持久化。
- try-with-resources语句:Java 7引入,自动关闭流,简化代码。
总结回顾
本节重点讲解了Java输入输出流的基本概念、分类及其核心类的使用方法。通过字节流和字符流的对比,理解了不同类型文件应选择不同的流类型。缓冲流的引入提高了读写效率,数据流则方便处理多种基本数据类型。通过典型实例,掌握了文件复制、数据存储等实用操作。理解常见误区,避免编码和效率问题。结合实际应用场景,增强了对输入输出流的理解和运用能力。
掌握本节内容不仅是顺利通过二级Java考试的关键,也是成为Java开发者的重要基础。