IO 是 Input/Output(输入/输出) 的缩写,代表了程序与外部环境(如文件、网络、设备等)之间进行数据交换的操作。在 Java 中,IO 操作广泛用于文件读取、写入、网络通信等场景。Java 提供了强大的 IO 类来简化这些操作,并按照不同的数据类型(如字节、字符)和数据源提供了不同的类。
根据数据处理的方式不同,Java 中的 IO 操作可以分为以下几大类:
Java IO 常用类如下表:
类别 | 输入类 | 输出类 |
---|---|---|
字节流 | InputStream |
OutputStream |
文件字节流 | FileInputStream |
FileOutputStream |
字符流 | Reader |
Writer |
文件字符流 | FileReader |
FileWriter |
缓冲流 | BufferedInputStream |
BufferedOutputStream |
缓冲字符流 | BufferedReader |
BufferedWriter |
Java 中的 IO 操作分为两类:字节流 和 字符流。它们的区别在于处理的数据类型不同。
字节流 以 8 位字节 为单位读取或写入数据,适合处理 二进制数据。字节流的常见用法是处理图片、视频、音频等非文本文件。字节流类的主要父类有:
InputStream
:字节输入流,用于从数据源读取字节。OutputStream
:字节输出流,用于将字节写入目标。常用字节流类包括 FileInputStream
、FileOutputStream
、BufferedInputStream
、BufferedOutputStream
等。
字符流 以 16 位字符 为单位进行数据处理,适合处理 文本数据,如字符串和文本文件。字符流类的主要父类有:
Reader
:字符输入流,用于读取字符数据。Writer
:字符输出流,用于写入字符数据。常用字符流类包括 FileReader
、FileWriter
、BufferedReader
、BufferedWriter
等。
区别点 | 字节流 | 字符流 |
---|---|---|
处理的数据类型 | 处理二进制数据,如图片、音频 | 处理文本数据,如文本文件、字符串 |
数据单位 | 以字节为单位(8 位) | 以字符为单位(16 位) |
使用场景 | 适用于非文本文件的处理 | 适用于文本文件或字符数据的处理 |
父类 | InputStream 和 OutputStream |
Reader 和 Writer |
常用类 | FileInputStream ,FileOutputStream |
FileReader ,FileWriter |
字节流主要用于处理非文本数据。Java 提供了丰富的字节流类来帮助开发者进行文件或网络数据的操作。
InputStream
是字节输入流的父类,定义了从不同的输入源(如文件、网络、内存缓冲区)读取字节的基本方法。
常用的 InputStream
子类包括:
FileInputStream
:用于从文件中读取字节数据。BufferedInputStream
:为其他输入流提供缓冲功能,提高读取效率。ByteArrayInputStream
:从字节数组中读取数据。OutputStream
是字节输出流的父类,定义了向不同的输出目标(如文件、网络、内存缓冲区)写入字节的基本方法。
常用的 OutputStream
子类包括:
FileOutputStream
:用于将字节数据写入文件。BufferedOutputStream
:为其他输出流提供缓冲功能,提高写入效率。ByteArrayOutputStream
:向字节数组中写入数据。通过 FileInputStream
读取二进制文件(如图片),并将其保存到字节数组中:
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputExample {
public static void main(String[] args) {
String filePath = "image.jpg"; // 文件路径
try (FileInputStream fis = new FileInputStream(filePath)) {
byte[] data = new byte[fis.available()];
fis.read(data); // 将文件内容读取到字节数组中
System.out.println("读取了 " + data.length + " 个字节的数据");
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过 FileOutputStream
将字节数据写入文件:
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputExample {
public static void main(String[] args) {
String filePath = "output.jpg"; // 输出文件路径
byte[] data = { /* 图片的字节数据 */ };
try (FileOutputStream fos = new FileOutputStream(filePath)) {
fos.write(data); // 将字节数据写入文件
System.out.println("写入了 " + data.length + " 个字节的数据");
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这两个例子中,使用了 try-with-resources
语法来确保流的正确关闭,防止资源泄漏。
字符流用于处理文本数据,如字符串或文本文件的读取和写入。字符流以 Reader
和 Writer
为父类,分别对应输入和输出操作。
Reader
是字符输入流的父类,用于从各种输入源(如文件、内存缓冲区、网络连接)读取字符数据。
常用的 Reader
子类包括:
FileReader
:从文件中读取字符数据。BufferedReader
:提供缓冲功能以提高读取效率。Writer
是字符输出流的父类,用于将字符数据写入输出目标(如文件、内存缓冲区、网络连接)。
常用的 Writer
子类包括:
FileWriter
:向文件写入字符数据。BufferedWriter
:提供缓冲功能以提高写入效率。通过 FileReader
和 BufferedReader
读取文本文件的内容:
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class FileReaderExample {
public static void main(String[] args) {
String filePath = "example.txt"; // 文件路径
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line); // 输出文件的每一行
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过 FileWriter
和 BufferedWriter
将文本数据写入文件:
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class FileWriterExample {
public static void main(String[] args) {
String filePath = "output.txt"; // 输出文件路径
String content = "这是写入文件的文本内容。";
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
bw.write(content); // 写入文本内容
bw.newLine(); // 换行
bw.write("这是另一行文本。");
System.out.println("文本内容已成功写入文件。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
结合读取和写入操作,展示如何读取一个文件的内容,并将其写入到另一个文件中。
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class FileCopyExample {
public static void main(String[] args) {
String inputFilePath = "input.txt"; // 输入文件路径
String outputFilePath = "output.txt"; // 输出文件路径
try (
BufferedReader br = new BufferedReader(new FileReader(inputFilePath));
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilePath))
) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line); // 将读取的行写入输出文件
bw.newLine(); // 写入换行符
}
System.out.println("文件内容已成功复制到新的文件。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例通过 BufferedReader
读取文本文件,并通过 BufferedWriter
将内容写入到另一个文件中,确保了高效读取和写入操作。
在进行 IO 操作时,未能正确关闭流对象会导致资源泄漏问题。Java 的 IO 操作通常涉及文件句柄、网络连接等有限资源,如果这些资源未能及时释放,可能会引发以下问题:
为了解决流泄漏问题,Java 提供了多种方法来确保流在使用后被正确关闭:
使用 try-finally
结构手动关闭流。
import java.io.FileInputStream;
import java.io.IOException;
public class ExplicitCloseExample {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("example.txt");
// 执行读取操作
} catch (IOException e) {
e.printStackTrace();
} finally {
// 确保在 finally 中关闭流
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
try-with-resources
从 Java 7 开始,提供了 try-with-resources
语法,该结构可以自动关闭实现了 AutoCloseable
接口的资源类,避免了手动关闭流的麻烦。
import java.io.FileInputStream;
import java.io.IOException;
public class TryWithResourcesExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("example.txt")) {
// 执行读取操作
} catch (IOException e) {
e.printStackTrace();
}
// 文件流会自动关闭
}
}
try-with-resources
是推荐的方式,它能够确保即使发生异常,也会自动关闭流,极大地减少了流泄漏的可能性。