Java I/O (Input/Output) 详解
Java I/O 是 Java 编程的重要组成部分,它提供了一套丰富的 API 用于处理各种输入和输出操作。本文将详细介绍 Java I/O 的基本概念、主要 API 的使用方法以及常见的应用场景。
一、Java I/O 概述
1.1 什么是 I/O
I/O 是 Input/Output(输入/输出)的缩写,指的是程序与外部环境进行数据交换的操作。输入操作从外部资源读取数据到程序中,输出操作将数据从程序写入到外部资源中。外部资源可以是文件、网络、控制台、设备等。
1.2 Java I/O 的分类
Java I/O 一般分为以下几类:
- 基础 I/O:包括字节流(
InputStream
和OutputStream
)和字符流(Reader
和Writer
)。 - 高级 I/O:包括缓冲流、数据流、对象流等。
- 基于 NIO(New I/O)的 I/O 操作。
二、字节流 API
字节流是最基本的 I/O 操作,主要用于处理二进制数据。字节流的基类主要有 InputStream
和 OutputStream
。
2.1 输入字节流(InputStream)
InputStream
是所有字节输入流的超类,提供了读取字节的方法。
常用子类:
FileInputStream
ByteArrayInputStream
FilterInputStream
常用方法:
java
public abstract class InputStream { public abstract int read() throws IOException; public int read(byte[] b) throws IOException; public int read(byte[] b, int off, int len) throws IOException; public void close() throws IOException; }
示例:
java
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class InputStreamExample { public static void main(String[] args) { try (InputStream inputStream = new FileInputStream("example.txt")) { int data; while ((data = inputStream.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } } }
2.2 输出字节流(OutputStream)
OutputStream
是所有字节输出流的超类,提供了写出字节的方法。
常用子类:
FileOutputStream
ByteArrayOutputStream
FilterOutputStream
常用方法:
java
public abstract class OutputStream { public abstract void write(int b) throws IOException; public void write(byte[] b) throws IOException; public void write(byte[] b, int off, int len) throws IOException; public void close() throws IOException; }
示例:
java
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class OutputStreamExample { public static void main(String[] args) { try (OutputStream outputStream = new FileOutputStream("example.txt")) { String data = "Hello, world!"; outputStream.write(data.getBytes()); } catch (IOException e) { e.printStackTrace(); } } }
三、字符流 API
字符流是专门用于处理字符数据的 I/O 操作。字符流的基类主要有 Reader
和 Writer
。
3.1 输入字符流(Reader)
Reader
是所有字符输入流的超类,提供了读取字符的方法。
常用子类:
FileReader
BufferedReader
InputStreamReader
常用方法:
java
public abstract class Reader { public abstract int read() throws IOException; public int read(char[] cbuf) throws IOException; public int read(char[] cbuf, int off, int len) throws IOException; public void close() throws IOException; }
示例:
java
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class ReaderExample { public static void main(String[] args) { try (Reader reader = new FileReader("example.txt"); BufferedReader bufferedReader = new BufferedReader(reader)) { String line; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
3.2 输出字符流(Writer)
Writer
是所有字符输出流的超类,提供了写出字符的方法。
常用子类:
FileWriter
BufferedWriter
OutputStreamWriter
常用方法:
java
public abstract class Writer { public abstract void write(int c) throws IOException; public void write(char[] cbuf) throws IOException; public void write(char[] cbuf, int off, int len) throws IOException; public void write(String str) throws IOException; public void close() throws IOException; }
示例:
java
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class WriterExample { public static void main(String[] args) { try (Writer writer = new FileWriter("example.txt"); BufferedWriter bufferedWriter = new BufferedWriter(writer)) { String data = "Hello, world!"; bufferedWriter.write(data); } catch (IOException e) { e.printStackTrace(); } } }
四、缓冲流
缓冲流提供了一个缓冲区,显著提升了 I/O 的效率。常用的缓冲流包括 BufferedInputStream
、BufferedOutputStream
、BufferedReader
和 BufferedWriter
。
4.1 缓冲字节输入流(BufferedInputStream)
java
import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class BufferedInputStreamExample { public static void main(String[] args) { try (InputStream inputStream = new FileInputStream("example.txt"); BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) { int data; while ((data = bufferedInputStream.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } } }
4.2 缓冲字节输出流(BufferedOutputStream)
java
import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class BufferedOutputStreamExample { public static void main(String[] args) { try (OutputStream outputStream = new FileOutputStream("example.txt"); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { String data = "Hello, world!"; bufferedOutputStream.write(data.getBytes()); } catch (IOException e) { e.printStackTrace(); } } }
4.3 缓冲字符输入流(BufferedReader)
上面的 ReaderExample
已经展示了如何使用 BufferedReader
,再来看一个读取文件中所有行并存入列表的例子:
java
import java.io.*; import java.util.*; public class BufferedReaderExample { public static void main(String[] args) { List<String> lines = new ArrayList<>(); try (Reader reader = new FileReader("example.txt"); BufferedReader bufferedReader = new BufferedReader(reader)) { String line; while ((line = bufferedReader.readLine()) != null) { lines.add(line); } } catch (IOException e) { e.printStackTrace(); } for (String line : lines) { System.out.println(line); } } }
4.4 缓冲字符输出流(BufferedWriter)
上面的 WriterExample
已经展示了如何使用 BufferedWriter
,再来看一个写入多行文本的例子:
java
import java.io.*; import java.util.*; public class BufferedWriterExample { public static void main(String[] args) { List<String> lines = Arrays.asList("First Line", "Second Line", "Third Line"); try (Writer writer = new FileWriter("example.txt"); BufferedWriter bufferedWriter = new BufferedWriter(writer)) { for (String line : lines) { bufferedWriter.write(line); bufferedWriter.newLine(); } } catch (IOException e) { e.printStackTrace(); } } }
五、数据流
数据流用于读写基本数据类型(如 int
、float
、double
)和 String
类型。
数据输入流(DataInputStream)
java
import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class DataInputStreamExample { public static void main(String[] args) { try (InputStream inputStream = new FileInputStream("example.dat"); DataInputStream dataInputStream = new DataInputStream(inputStream)) { int intValue = dataInputStream.readInt(); float floatValue = dataInputStream.readFloat(); String strValue = dataInputStream.readUTF(); System.out.println("Integer: " + intValue); System.out.println("Float: " + floatValue); System.out.println("String: " + strValue); } catch (IOException e) { e.printStackTrace(); } } }
数据输出流(DataOutputStream)
java
import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class DataOutputStreamExample { public static void main(String[] args) { try (OutputStream outputStream = new FileOutputStream("example.dat"); DataOutputStream dataOutputStream = new DataOutputStream(outputStream)) { dataOutputStream.writeInt(123); dataOutputStream.writeFloat(45.67f); dataOutputStream.writeUTF("Hello, DataOutputStream!"); } catch (IOException e) { e.printStackTrace(); } } }
六、对象流
对象流用于序列化和反序列化对象,对象流的主要类是 ObjectInputStream
和 ObjectOutputStream
。
对象输入流(ObjectInputStream)
java
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class ObjectInputStreamExample { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("example.obj"))) { Student student = (Student) ois.readObject(); System.out.println("Name: " + student.getName()); System.out.println("Age: " + student.getAge()); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
对象输出流(ObjectOutputStream)
java
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ObjectOutputStreamExample { public static void main(String[] args) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("example.obj"))) { Student student = new Student("John Doe", 22); oos.writeObject(student); } catch (IOException e) { e.printStackTrace(); } } }
示例对象类(Student)
java
import java.io.Serializable; public class Student implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
七、NIO(新 I/O)
NIO(New I/O)是 Java 1.4 引入的一组新的 I/O API,能够提供非阻塞 I/O 操作,拥有比传统 I/O 更高的性能和更复杂的功能。NIO 主要组件包括 Channel
、Buffer
和 Selector
。
7.1 通道(Channel)
通道是 I/O 操作的载体,可以用于读取和写入数据。
示例:FileChannel
java
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileChannelExample { public static void main(String[] args) { try (FileChannel fileChannel = new FileInputStream("source.txt").getChannel(); FileChannel targetChannel = new FileOutputStream("target.txt").getChannel()) { ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead; while ((bytesRead = fileChannel.read(buffer)) != -1) { buffer.flip(); // 切换到读取模式 targetChannel.write(buffer); buffer.clear(); // 清空缓冲区以便下次写入 } } catch (IOException e) { e.printStackTrace(); } } }
7.2 缓冲区(Buffer)
缓冲区是在数据传输中临时存储数据的地方,NIO 的核心概念之一。
示例:ByteBuffer
java
import java.nio.ByteBuffer; public class ByteBufferExample { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(256); buffer.put((byte) 'H'); buffer.put((byte) 'e'); buffer.put((byte) 'l'); buffer.put((byte) 'l'); buffer.put((byte) 'o'); buffer.flip(); // 将缓冲区切换到读取模式 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } } }
7.3 选择器(Selector)
选择器用于管理多个通道,可以用于处理非阻塞 I/O 操作。 示例如下:
java
public class SelectorExample { public static void main(String[] args) { try (Selector selector = Selector.open(); ServerSocketChannel serverChannel = ServerSocketChannel.open()) { serverChannel.bind(new InetSocketAddress(8080)); serverChannel.configureBlocking(false); serverChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select(); // 阻塞直到有通道准备好 Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> iter = selectedKeys.iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); if (key.isAcceptable()) { // 接受连接请求 ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel client = server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 处理读请求 SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(256); int bytesRead = client.read(buffer); if (bytesRead == -1) { client.close(); } else { buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } } } iter.remove(); // 移除已处理的键 } } } catch (IOException e) { e.printStackTrace(); } } }
八、常见场景及应用
8.1 文件读写
处理文件读写是最常见的 I/O 操作,使用 FileInputStream、FileOutputStream、FileReader 和 FileWriter 等类即可完成。
8.2 序列化与反序列化
使用 ObjectInputStream 和 ObjectOutputStream,可以轻松实现对象的序列化和反序列化,适用于保存对象的状态或远程传输对象。
8.3 缓冲读写
为提升 I/O 性能,Buffer流如 BufferedReader 和 BufferedWriter 是常用工具,适用于读写大量数据或频繁 I/O 操作的场景。
8.4 网络编程
NIO 的通道(Channel)和选择器(Selector)机制非常适合非阻塞的高性能网络编程,如处理多客户端连接的服务器。
8.5 数据流
使用 DataInputStream 和 DataOutputStream 可以方便地读写基本数据类型和字符串,适用于需要进行数据交换或通讯的场景,如网络协议实现。