Java中的I/O流
Java中的I/O流(Input/Output Streams)是用于处理输入和输出操作的类。这些流可以用来读取或写入数据,无论是从文件、网络连接还是内存缓冲区。Java I/O API位于java.io
包中,并分为字节流和字符流两大类。
字节流
在Java中,字节流主要用于处理以字节为单位的数据输入和输出操作。它们非常适合处理二进制数据,如图像文件、音频文件等,也可以用于文本文件的读写(虽然对于文本文件,通常更推荐使用字符流)。字节流的核心类位于java.io包中,主要包括抽象类InputStream和OutputStream及其子类。
InputStream
:抽象类,所有字节输入流的超类。OutputStream
:抽象类,所有字节输出流的超类。FileInputStream
:用于从文件系统中的某个文件中读取字节。FileOutputStream
:用于向文件系统中的某个文件写入字节。BufferedInputStream
和BufferedOutputStream
:通过内部缓冲区提高性能。ByteArrayInputStream
和ByteArrayOutputStream
:在内存中以字节数组的形式存储数据。DataInputStream
和DataOutputStream
:允许按基本数据类型读写数据。ObjectInputStream
和ObjectOutputStream
:用于序列化和反序列化对象。
1. InputStream
(抽象类)
- 作用:所有字节输入流的超类,定义了从源读取字节的基本方法(如
read()
)。 - 使用范围:作为其他字节输入流的基类,不直接实例化。
- 示例代码:
// 通常通过子类使用,如 FileInputStream
2. OutputStream
(抽象类)
- 作用:所有字节输出流的超类,定义了向目标写入字节的基本方法(如
write()
)。 - 使用范围:作为其他字节输出流的基类,不直接实例化。
- 示例代码:
// 通常通过子类使用,如 FileOutputStream
3. FileInputStream
- 作用:从文件系统读取字节数据。
- 使用范围:需要读取本地文件内容的场景。
- 示例代码:
try (FileInputStream fis = new FileInputStream("input.txt")) { int data; while ((data = fis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
4. FileOutputStream
- 作用:向文件系统写入字节数据。
- 使用范围:需要向本地文件写入内容的场景。
- 示例代码:
try (FileOutputStream fos = new FileOutputStream("output.txt")) { String text = "Hello, World!"; fos.write(text.getBytes()); } catch (IOException e) { e.printStackTrace(); }
5. BufferedInputStream
- 作用:通过内部缓冲区提高字节输入流的读取性能。
- 使用范围:需要高效读取大文件或频繁读取小数据块的场景。
- 示例代码:
try (FileInputStream fis = new FileInputStream("input.txt"); BufferedInputStream bis = new BufferedInputStream(fis)) { int data; while ((data = bis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
6. BufferedOutputStream
- 作用:通过内部缓冲区提高字节输出流的写入性能。
- 使用范围:需要高效写入大文件或频繁写入小数据块的场景。
- 示例代码:
try (FileOutputStream fos = new FileOutputStream("output.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos)) { String text = "Hello, Buffered World!"; bos.write(text.getBytes()); bos.flush(); // 确保缓冲区数据写入文件 } catch (IOException e) { e.printStackTrace(); }
7. ByteArrayInputStream
- 作用:从内存中的字节数组读取数据。
- 使用范围:需要从字节数组模拟输入流的场景(如测试或数据处理)。
- 示例代码:
byte[] data = "Hello, ByteArray!".getBytes(); try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) { int byteValue; while ((byteValue = bais.read()) != -1) { System.out.print((char) byteValue); } } catch (IOException e) { e.printStackTrace(); }
8. ByteArrayOutputStream
- 作用:向内存中的字节数组写入数据。
- 使用范围:需要将数据写入字节数组的场景(如动态生成内容)。
- 示例代码:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { String text = "Hello, ByteArrayOutputStream!"; baos.write(text.getBytes()); byte[] result = baos.toByteArray(); // 获取字节数组 System.out.println(new String(result)); } catch (IOException e) { e.printStackTrace(); }
9. DataInputStream
- 作用:允许按基本数据类型(如
int
,double
)读取数据。 - 使用范围:需要从流中读取结构化数据的场景。
- 示例代码:
try (DataInputStream dis = new DataInputStream( new BufferedInputStream( new FileInputStream("data.bin")))) { int num = dis.readInt(); double value = dis.readDouble(); System.out.println("Read: " + num + ", " + value); } catch (IOException e) { e.printStackTrace(); }
10. DataOutputStream
- 作用:允许按基本数据类型写入数据。
- 使用范围:需要向流中写入结构化数据的场景。
- 示例代码:
try (DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream("data.bin")))) { dos.writeInt(42); dos.writeDouble(3.1415); dos.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
11. ObjectInputStream
- 作用:从流中反序列化对象。
- 使用范围:需要读取序列化对象的场景(如网络传输或文件存储)。
- 示例代码:
try (ObjectInputStream ois = new ObjectInputStream( new FileInputStream("object.dat"))) { MyObject obj = (MyObject) ois.readObject(); System.out.println(obj); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
12. ObjectOutputStream
- 作用:将对象序列化到流中。
- 使用范围:需要写入序列化对象的场景(如网络传输或文件存储)。
- 示例代码:
try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("object.dat"))) { MyObject obj = new MyObject("Test", 123); oos.writeObject(obj); oos.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
补充说明
- 资源管理:使用
try-with-resources
语法(如try (InputStream is = ...)
)自动关闭流,避免资源泄漏。 - 序列化要求:对象需实现
Serializable
接口才能被ObjectInputStream
/ObjectOutputStream
处理。 - 性能优化:缓冲流(
BufferedInputStream
/BufferedOutputStream
)通过减少 I/O 操作次数显著提升性能。以下是 Java 中常用输入输出流类的作用、使用范围及示例代码:
1. InputStream
(抽象类)
- 作用:所有字节输入流的超类,定义了从源读取字节的基本方法(如
read()
)。 - 使用范围:作为其他字节输入流的基类,不直接实例化。
- 示例代码:
// 通常通过子类使用,如 FileInputStream
2. OutputStream
(抽象类)
- 作用:所有字节输出流的超类,定义了向目标写入字节的基本方法(如
write()
)。 - 使用范围:作为其他字节输出流的基类,不直接实例化。
- 示例代码:
// 通常通过子类使用,如 FileOutputStream
3. FileInputStream
- 作用:从文件系统读取字节数据。
- 使用范围:需要读取本地文件内容的场景。
- 示例代码:
try (FileInputStream fis = new FileInputStream("input.txt")) { int data; while ((data = fis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
4. FileOutputStream
- 作用:向文件系统写入字节数据。
- 使用范围:需要向本地文件写入内容的场景。
- 示例代码:
try (FileOutputStream fos = new FileOutputStream("output.txt")) { String text = "Hello, World!"; fos.write(text.getBytes()); } catch (IOException e) { e.printStackTrace(); }
5. BufferedInputStream
- 作用:通过内部缓冲区提高字节输入流的读取性能。
- 使用范围:需要高效读取大文件或频繁读取小数据块的场景。
- 示例代码:
try (FileInputStream fis = new FileInputStream("input.txt"); BufferedInputStream bis = new BufferedInputStream(fis)) { int data; while ((data = bis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
6. BufferedOutputStream
- 作用:通过内部缓冲区提高字节输出流的写入性能。
- 使用范围:需要高效写入大文件或频繁写入小数据块的场景。
- 示例代码:
try (FileOutputStream fos = new FileOutputStream("output.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos)) { String text = "Hello, Buffered World!"; bos.write(text.getBytes()); bos.flush(); // 确保缓冲区数据写入文件 } catch (IOException e) { e.printStackTrace(); }
7. ByteArrayInputStream
- 作用:从内存中的字节数组读取数据。
- 使用范围:需要从字节数组模拟输入流的场景(如测试或数据处理)。
- 示例代码:
byte[] data = "Hello, ByteArray!".getBytes(); try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) { int byteValue; while ((byteValue = bais.read()) != -1) { System.out.print((char) byteValue); } } catch (IOException e) { e.printStackTrace(); }
8. ByteArrayOutputStream
- 作用:向内存中的字节数组写入数据。
- 使用范围:需要将数据写入字节数组的场景(如动态生成内容)。
- 示例代码:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { String text = "Hello, ByteArrayOutputStream!"; baos.write(text.getBytes()); byte[] result = baos.toByteArray(); // 获取字节数组 System.out.println(new String(result)); } catch (IOException e) { e.printStackTrace(); }
9. DataInputStream
- 作用:允许按基本数据类型(如
int
,double
)读取数据。 - 使用范围:需要从流中读取结构化数据的场景。
- 示例代码:
try (DataInputStream dis = new DataInputStream( new BufferedInputStream( new FileInputStream("data.bin")))) { int num = dis.readInt(); double value = dis.readDouble(); System.out.println("Read: " + num + ", " + value); } catch (IOException e) { e.printStackTrace(); }
10. DataOutputStream
- 作用:允许按基本数据类型写入数据。
- 使用范围:需要向流中写入结构化数据的场景。
- 示例代码:
try (DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream("data.bin")))) { dos.writeInt(42); dos.writeDouble(3.1415); dos.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
11. ObjectInputStream
- 作用:从流中反序列化对象。
- 使用范围:需要读取序列化对象的场景(如网络传输或文件存储)。
- 示例代码:
try (ObjectInputStream ois = new ObjectInputStream( new FileInputStream("object.dat"))) { MyObject obj = (MyObject) ois.readObject(); System.out.println(obj); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
12. ObjectOutputStream
- 作用:将对象序列化到流中。
- 使用范围:需要写入序列化对象的场景(如网络传输或文件存储)。
- 示例代码:
try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("object.dat"))) { MyObject obj = new MyObject("Test", 123); oos.writeObject(obj); oos.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
补充说明
- 资源管理:使用
try-with-resources
语法(如try (InputStream is = ...)
)自动关闭流,避免资源泄漏。 - 序列化要求:对象需实现
Serializable
接口才能被ObjectInputStream
/ObjectOutputStream
处理。 - 性能优化:缓冲流(
BufferedInputStream
/BufferedOutputStream
)通过减少 I/O 操作次数显著提升性能。
字符流
在Java中,字符流用于处理以字符为单位的数据输入和输出操作。与字节流不同,字符流专门处理文本数据,它们基于16位的Unicode字符集进行编码和解码,这使得字符流非常适合于读写文本文件或其他文本数据源。字符流的核心类位于java.io包中,主要包括抽象类Reader和Writer及其子类。
Reader
:抽象类,所有字符输入流的超类。Writer
:抽象类,所有字符输出流的超类。FileReader
和FileWriter
:分别用于从文件读取字符和向文件写入字符。BufferedReader
和BufferedWriter
:通过内部缓冲区提高性能。CharArrayReader
和CharArrayWriter
:在内存中以字符数组的形式存储数据。InputStreamReader
和OutputStreamWriter
:桥接字节流和字符流,支持指定字符编码。PrintWriter
:提供格式化的打印功能。
1. Reader
(抽象类)
- 作用:所有字符输入流的超类,定义了从源读取字符的基本方法(如
read()
)。 - 使用范围:作为其他字符输入流的基类,不直接实例化。
- 示例代码:
// 通常通过子类使用,如 FileReader
2. Writer
(抽象类)
- 作用:所有字符输出流的超类,定义了向目标写入字符的基本方法(如
write()
)。 - 使用范围:作为其他字符输出流的基类,不直接实例化。
- 示例代码:
// 通常通过子类使用,如 FileWriter
3. FileReader
- 作用:从文件系统读取字符数据。
- 使用范围:需要读取本地文本文件的场景。
- 示例代码:
try (FileReader fr = new FileReader("text.txt")) { int data; while ((data = fr.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
4. FileWriter
- 作用:向文件系统写入字符数据。
- 使用范围:需要向本地文本文件写入内容的场景。
- 示例代码:
try (FileWriter fw = new FileWriter("output.txt")) { String text = "Hello, FileWriter!"; fw.write(text); fw.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
5. BufferedReader
- 作用:通过内部缓冲区提高字符输入流的读取性能。
- 使用范围:需要高效读取大文本文件或频繁读取小数据块的场景。
- 示例代码:
try (FileReader fr = new FileReader("text.txt"); BufferedReader br = new BufferedReader(fr)) { String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
6. BufferedWriter
- 作用:通过内部缓冲区提高字符输出流的写入性能。
- 使用范围:需要高效写入大文本文件或频繁写入小数据块的场景。
- 示例代码:
try (FileWriter fw = new FileWriter("output.txt"); BufferedWriter bw = new BufferedWriter(fw)) { bw.write("Hello, BufferedWriter!"); bw.newLine(); // 写入换行符 bw.flush(); // 确保缓冲区数据写入文件 } catch (IOException e) { e.printStackTrace(); }
7. CharArrayReader
- 作用:从内存中的字符数组读取数据。
- 使用范围:需要从字符数组模拟输入流的场景(如测试或数据处理)。
- 示例代码:
char[] data = "Hello, CharArray!".toCharArray(); try (CharArrayReader car = new CharArrayReader(data)) { int charValue; while ((charValue = car.read()) != -1) { System.out.print((char) charValue); } } catch (IOException e) { e.printStackTrace(); }
8. CharArrayWriter
- 作用:向内存中的字符数组写入数据。
- 使用范围:需要将数据写入字符数组的场景(如动态生成内容)。
- 示例代码:
try (CharArrayWriter caw = new CharArrayWriter()) { String text = "Hello, CharArrayWriter!"; caw.write(text); char[] result = caw.toCharArray(); // 获取字符数组 System.out.println(new String(result)); } catch (IOException e) { e.printStackTrace(); }
9. InputStreamReader
- 作用:将字节流转换为字符流,支持指定字符编码(如 UTF-8)。
- 使用范围:需要按特定编码读取字节数据的场景(如网络传输或文件)。
- 示例代码:
try (FileInputStream fis = new FileInputStream("text.bin"); InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8)) { int data; while ((data = isr.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
10. OutputStreamWriter
- 作用:将字符流转换为字节流,支持指定字符编码(如 UTF-8)。
- 使用范围:需要按特定编码写入字节数据的场景(如网络传输或文件)。
- 示例代码:
try (FileOutputStream fos = new FileOutputStream("output.bin"); OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) { String text = "Hello, OutputStreamWriter!"; osw.write(text); osw.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
11. PrintWriter
- 作用:提供格式化的字符输出功能(如
printf
、println
)。 - 使用范围:需要向控制台或文件输出格式化文本的场景。
- 示例代码:
try (PrintWriter pw = new PrintWriter(new FileWriter("output.txt"))) { pw.println("Hello, PrintWriter!"); pw.printf("Number: %d, Pi: %.2f", 42, 3.1415); pw.flush(); // 确保数据写入文件 } catch (IOException e) { e.printStackTrace(); }
补充说明
- 资源管理:使用
try-with-resources
语法自动关闭流,避免资源泄漏。 - 字符编码:通过
InputStreamReader
/OutputStreamWriter
指定编码(如 UTF-8),确保跨平台一致性。 - 性能优化:缓冲流(
BufferedReader
/BufferedWriter
)通过减少 I/O 操作次数显著提升性能。 - 格式化输出:
PrintWriter
支持类似System.out.printf
的格式化方法。
总结
- 字节流:适合处理二进制数据。
- 字符流:适合处理文本数据,自动处理字符编码和换行符。