跳到主要内容Java IO 流:从文件操作到网络通信 | 极客日志Javajava
Java IO 流:从文件操作到网络通信
Java IO 流是处理输入输出的 API,位于 java.io 包中,用于程序与外部设备间传输数据。文章详细阐述了按流向(输入/输出)和数据类型(字节/字符)的分类,对比了 FileInputStream/FileOutputStream 与 FileReader/Writer 的使用差异。通过代码示例展示了 try-with-resources 资源管理、BufferedStream 效率优化、InputStreamReader 编码转换及 Serializable 对象序列化的具体实现,并总结了文件未找到、权限不足、乱码等常见问题的排查方法。
5.1 IO 流概述
5.1.1 学习目标与重点提示
学习目标:理解 IO 流的基本概念和分类,掌握字节流、字符流的使用方法,了解缓冲流、转换流、对象流等高级流的应用。
重点:字节流与字符流的区别、缓冲流的原理、对象的序列化与反序列化。
5.1.2 IO 流的基本概念
IO 流(Input/Output Stream)是 Java 中用于处理输入和输出的 API,位于 java.io 包中。IO 流的作用是在程序和外部设备之间传输数据,外部设备包括文件、网络、键盘、显示器等。
- 按数据流向分:
- 输入流(Input Stream):从外部设备读取数据到程序中。
- 输出流(Output Stream):从程序中写入数据到外部设备中。
- 按数据类型分:
- 字节流(Byte Stream):处理字节数据(如图片、音频、视频等二进制文件)。
- 字符流(Character Stream):处理字符数据(如文本文件),自动处理字符编码。
5.2 字节流
字节流是处理字节数据的流,所有字节流类都继承自 InputStream(输入字节流)或 OutputStream(输出字节流)。
5.2.1 字节输入流(InputStream)
- FileInputStream:从文件中读取字节数据。
- ByteArrayInputStream:从字节数组中读取字节数据。
- DataInputStream:读取基本数据类型的数据。
示例:使用 FileInputStream 读取文件的内容
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestFileInputStream {
public static void main(String[] args) {
File file = new File("test.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, length));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
⚠️ 注意:在使用完 IO 流后,必须关闭流以释放资源。可以使用 try-catch-finally 语句或 try-with-resources 语句(JDK 7 及以后)来关闭流。
使用 try-with-resources 语句的示例:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestFileInputStream2 {
public static void main(String[] args) {
File file = new File("test.txt");
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, length));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.2.2 字节输出流(OutputStream)
- FileOutputStream:向文件中写入字节数据。
- ByteArrayOutputStream:向字节数组中写入字节数据。
- DataOutputStream:写入基本数据类型的数据。
示例:使用 FileOutputStream 向文件中写入内容
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFileOutputStream {
public static void main(String[] args) {
File file = new File("test.txt");
try (FileOutputStream fos = new FileOutputStream(file)) {
String content = "Hello, Java IO Stream!";
fos.write(content.getBytes());
System.out.println("内容已写入文件");
} catch (IOException e) {
e.printStackTrace();
}
}
}
⚠️ 注意:使用 FileOutputStream 向文件中写入内容时,如果文件不存在,会自动创建文件;如果文件已存在,会覆盖文件的内容。如果需要在文件的末尾追加内容,可以使用 FileOutputStream(file, true) 构造方法。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFileOutputStream2 {
public static void main(String[] args) {
File file = new File("test.txt");
try (FileOutputStream fos = new FileOutputStream(file, true)) {
String content = "\nThis is additional content!";
fos.write(content.getBytes());
System.out.println("内容已追加到文件");
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.3 字符流
字符流是处理字符数据的流,所有字符流类都继承自 Reader(输入字符流)或 Writer(输出字符流)。字符流自动处理字符编码,避免了字节流处理字符数据时的编码问题。
5.3.1 字符输入流(Reader)
- FileReader:从文件中读取字符数据。
- CharArrayReader:从字符数组中读取字符数据。
- BufferedReader:缓冲字符输入流,提高读取效率。
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestFileReader {
public static void main(String[] args) {
File file = new File("test.txt");
try (FileReader fr = new FileReader(file)) {
char[] buffer = new char[1024];
int length;
while ((length = fr.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, length));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 BufferedReader 提高读取效率:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestBufferedReader {
public static void main(String[] args) {
File file = new File("test.txt");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.3.2 字符输出流(Writer)
- FileWriter:向文件中写入字符数据。
- CharArrayWriter:向字符数组中写入字符数据。
- BufferedWriter:缓冲字符输出流,提高写入效率。
示例:使用 FileWriter 向文件中写入内容
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestFileWriter {
public static void main(String[] args) {
File file = new File("test.txt");
try (FileWriter fw = new FileWriter(file)) {
String content = "Hello, Java Character Stream!";
fw.write(content);
System.out.println("内容已写入文件");
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 BufferedWriter 提高写入效率:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestBufferedWriter {
public static void main(String[] args) {
File file = new File("test.txt");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
String content = "Hello, Java Character Stream!";
bw.write(content);
bw.newLine();
bw.write("This is additional content!");
System.out.println("内容已写入文件");
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.4 高级流
高级流是在字节流或字符流的基础上进行功能增强的流,常用的高级流包括:
5.4.1 缓冲流
缓冲流(Buffered Stream)通过在内存中设置缓冲区,减少了对磁盘的 IO 操作,提高了读取和写入效率。常用的缓冲流类包括:
- BufferedInputStream:缓冲字节输入流。
- BufferedOutputStream:缓冲字节输出流。
- BufferedReader:缓冲字符输入流。
- BufferedWriter:缓冲字符输出流。
import java.io.*;
public class TestCopyFile {
public static void main(String[] args) {
File sourceFile = new File("source.txt");
File targetFile = new File("target.txt");
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {
byte[] buffer = new byte[1024];
int length;
while ((length = bis.read(buffer)) != -1) {
bos.write(buffer, 0, length);
}
System.out.println("文件已复制");
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.4.2 转换流
转换流(Convert Stream)用于在字节流和字符流之间进行转换。常用的转换流类包括:
- InputStreamReader:将字节输入流转换为字符输入流。
- OutputStreamWriter:将字符输出流转换为字节输出流。
import java.io.*;
public class TestInputStreamReader {
public static void main(String[] args) {
File file = new File("test.txt");
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
public class TestOutputStreamWriter {
public static void main(String[] args) {
File file = new File("test.txt");
try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
BufferedWriter bw = new BufferedWriter(osw)) {
String content = "你好,Java 转换流!";
bw.write(content);
bw.newLine();
bw.write("这是追加的内容!");
System.out.println("内容已写入文件");
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.4.3 对象流
对象流(Object Stream)用于将 Java 对象序列化和反序列化。序列化是将 Java 对象转换为字节序列的过程,反序列化是将字节序列转换为 Java 对象的过程。常用的对象流类包括:
- ObjectInputStream:用于反序列化对象。
- ObjectOutputStream:用于序列化对象。
⚠️ 注意:要实现序列化的对象必须实现 Serializable 接口,该接口没有任何方法,只是一个标记接口。
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private int age;
public Student(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + '}';
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class TestObjectOutputStream {
public static void main(String[] args) {
File file = new File("student.dat");
Student student = new Student("1001", "张三", 18);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
oos.writeObject(student);
System.out.println("对象已序列化");
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例:将文件中的字节序列反序列化为 Student 对象
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class TestObjectInputStream {
public static void main(String[] args) {
File file = new File("student.dat");
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
Student student = (Student) ois.readObject();
System.out.println("对象已反序列化:" + student);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
5.5 常见问题与解决方案
5.5.1 文件未找到
问题:程序抛出 FileNotFoundException 异常,提示'系统找不到指定的文件'。
解决方案:检查文件的路径是否正确,确保文件存在。例如:
File file = new File("test.txt");
System.out.println(file.exists());
5.5.2 文件读写权限不足
问题:程序抛出 SecurityException 异常,提示'拒绝访问'。
解决方案:检查文件的读写权限,确保程序有足够的权限读取或写入文件。
5.5.3 编码问题
InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");
5.5.4 对象未实现 Serializable 接口
问题:程序抛出 NotSerializableException 异常,提示'类未实现 Serializable 接口'。
解决方案:让需要序列化的类实现 Serializable 接口。
总结
本章我们学习了 Java 的 IO 流,包括字节流、字符流和高级流的使用方法。其中,字节流与字符流的区别、缓冲流的原理、对象的序列化与反序列化是本章的重点内容。从下一章开始,我们将学习 Java 的多线程、网络编程等内容。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online