引言
在Java编程中,输入和输出(I/O)操作是必不可少的部分。Java I/O通过一系列流(Stream)类和方法,支持文件操作、控制台输入输出、网络I/O等多种I/O操作。本文将详细介绍Java I/O的基础概念、文件操作、字符流与字节流的区别、序列化与反序列化以及新的I/O(NIO)等内容,并通过表格进行总结和示范。
Java I/O基础概念
流的概念
流(Stream)是指数据的流动,是一个顺序读写数据的抽象。Java定义了两种基本类型的流:
- 字节流:用于处理字节数据,最基础的类是
InputStream
和OutputStream
。 - 字符流:用于处理字符数据,最基础的类是
Reader
和Writer
。
流的分类
Java I/O流可以按照数据类型分类为字节流和字符流,也可以按照数据流向分为输入流和输出流。
类型 | 输入流 | 输出流 |
---|---|---|
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
文件与目录操作
文件类(File)
File
类表示文件或目录,可以对其进行创建、删除、获取信息等操作。
import java.io.File;
import java.io.IOException;public class FileExample {public static void main(String[] args) {// 创建一个File对象File file = new File("example.txt");try {// 创建新文件if (file.createNewFile()) {System.out.println("File created: " + file.getName());} else {System.out.println("File already exists.");}// 获取文件信息System.out.println("Absolute path: " + file.getAbsolutePath());System.out.println("Writable: " + file.canWrite());System.out.println("Readable: " + file.canRead());System.out.println("File size in bytes: " + file.length());} catch (IOException e) {System.out.println("An error occurred.");e.printStackTrace();}}
}
文件与目录操作方法表
方法 | 描述 | 示例 |
---|---|---|
createNewFile() | 创建一个新的文件 | file.createNewFile(); |
delete() | 删除文件或目录 | file.delete(); |
exists() | 判断文件或目录是否存在 | file.exists(); |
getAbsolutePath() | 获取文件的绝对路径 | file.getAbsolutePath(); |
canWrite() | 判断文件是否可写 | file.canWrite(); |
canRead() | 判断文件是否可读 | file.canRead(); |
length() | 获取文件大小(字节) | file.length(); |
字符流和字节流
字节流
字节流用于处理字节数据,通过InputStream
和OutputStream
类及其子类进行输入输出操作。
示例:使用FileInputStream
和FileOutputStream
进行文件字节操作
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class ByteStreamExample {public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("input.txt");FileOutputStream fos = new FileOutputStream("output.txt")) {int byteData;// 逐字节读取数据while ((byteData = fis.read()) != -1) {// 逐字节写入数据fos.write(byteData);}} catch (IOException e) {e.printStackTrace();}}
}
字符流
字符流用于处理字符数据,通过Reader
和Writer
类及其子类进行输入输出操作。
示例:使用FileReader
和FileWriter
进行文件字符操作
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;public class CharStreamExample {public static void main(String[] args) {try (FileReader fr = new FileReader("input.txt");FileWriter fw = new FileWriter("output.txt")) {int charData;// 逐字符读取数据while ((charData = fr.read()) != -1) {// 逐字符写入数据fw.write(charData);}} catch (IOException e) {e.printStackTrace();}}
}
字符流和字节流的比较表
特性 | 字节流 | 字符流 |
---|---|---|
基本类 | InputStream 和 OutputStream | Reader 和 Writer |
数据处理单位 | 字节(8位) | 字符(16位) |
适用场景 | 二进制数据(如图像、音频) | 文本数据(如文本文件) |
典型实现类 | FileInputStream , FileOutputStream | FileReader , FileWriter |
序列化与反序列化
序列化
序列化是将对象转换为字节流并写到文件或网络中的过程。实现Serializable
接口的类可以被序列化。
示例:对象序列化
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;class Person implements Serializable {private static final long serialVersionUID = 1L;String name;int age;public Person(String name, int age) {this.name = name;this.age = age;}
}public class SerializationExample {public static void main(String[] args) {Person person = new Person("John", 30);try (FileOutputStream fos = new FileOutputStream("person.ser");ObjectOutputStream oos = new ObjectOutputStream(fos)) {oos.writeObject(person);} catch (IOException e) {e.printStackTrace();}}
}
反序列化
反序列化是将字节流转换为对象的过程。读取序列化文件时使用ObjectInputStream
。
示例:对象反序列化
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;public class DeserializationExample {public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("person.ser");ObjectInputStream ois = new ObjectInputStream(fis)) {Person person = (Person) ois.readObject();System.out.println("Name: " + person.name);System.out.println("Age: " + person.age);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
序列化与反序列化的表格总结
概念 | 描述 | 示例 |
---|---|---|
序列化 | 将对象转换为字节流并写到文件或网络中 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("file.ser")); oos.writeObject(object); |
反序列化 | 将字节流转换为对象 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file.ser")); Object obj = ois.readObject(); |
必需接口 | 需要实现 Serializable 接口 | class Person implements Serializable { ... } |
序列化ID | 建议定义 serialVersionUID 字段应避免反序列化不兼容 | private static final long serialVersionUID = 1L; |
新的I/O (NIO)
Java的新的I/O(NIO)引入了多个新概念,如缓冲区、通道和选择器。这些概念提供了更高效的I/O处理,特别是在处理大数据和高性能网络应用方面。下面我们将详细介绍这些概念。
缓冲区(Buffer)
缓冲区是NIO数据操作的基础,用于存储和操作数据。Java NIO提供了多种类型的缓冲区,比如ByteBuffer
、CharBuffer
等。
示例:使用ByteBuffer
import java.nio.ByteBuffer;public class BufferExample {public static void main(String[] args) {// 创建一个大小为10的字节缓冲区ByteBuffer buffer = ByteBuffer.allocate(10);// 写入数据到缓冲区buffer.put((byte) 1);buffer.put((byte) 2);// 切换到读模式buffer.flip();// 读取缓冲区中的数据while (buffer.hasRemaining()) {byte data = buffer.get();System.out.println(data);}}
}
通道(Channel)
通道是一个连接数据源和缓冲区的通道,数据可以通过通道从数据源读入缓冲区,或从缓冲区写入到数据源。常用的通道有FileChannel
、SocketChannel
、ServerSocketChannel
等。
示例:使用FileChannel
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;public class ChannelExample {public static void main(String[] args) {// 文件路径Path path = Path.of("example.txt");// 使用文件通道写入数据try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {ByteBuffer buffer = ByteBuffer.allocate(64);buffer.put("Hello, NIO!".getBytes());buffer.flip();fileChannel.write(buffer);} catch (IOException e) {e.printStackTrace();}// 使用文件通道读取数据try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {ByteBuffer buffer = ByteBuffer.allocate(64);fileChannel.read(buffer);buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}} catch (IOException e) {e.printStackTrace();}}
}
选择器(Selector)
选择器是NIO中的多路复用器,可以用于管理多个通道,特别适用于网络编程。Selector
与SelectableChannel
配合使用,可以高效地处理非阻塞I/O操作。
示例:使用Selector
进行非阻塞I/O
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class SelectorExample {public static void main(String[] args) {try {// 打开选择器Selector selector = Selector.open();// 打开服务器套接字通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);// 将通道注册到选择器,并监听接受事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 循环等待事件while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectedKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();if (key.isAcceptable()) {// 接受新连接ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel socketChannel = serverChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {// 读取数据SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(256);socketChannel.read(buffer);buffer.flip();System.out.println("Received: " + new String(buffer.array()).trim());}}}} catch (IOException e) {e.printStackTrace();}}
}
NIO关键概念表格总结
概念 | 描述 | 示例 |
---|---|---|
缓冲区(Buffer) | 用于存储数据的容器,可以是字节、字符、短整型等 | ByteBuffer buffer = ByteBuffer.allocate(10); |
通道(Channel) | 用于连接数据源与缓冲区,实现I/O操作 | FileChannel.open(path, StandardOpenOption.READ); |
选择器(Selector) | 用于管理多个通道,实现非阻塞I/O的多路复用 | Selector.open(); selector.select(); |
表格总结
文件与目录操作方法表
方法 | 描述 | 示例 |
---|---|---|
createNewFile() | 创建一个新的文件 | file.createNewFile(); |
delete() | 删除文件或目录 | file.delete(); |
exists() | 判断文件或目录是否存在 | file.exists(); |
getAbsolutePath() | 获取文件的绝对路径 | file.getAbsolutePath(); |
canWrite() | 判断文件是否可写 | file.canWrite(); |
canRead() | 判断文件是否可读 | file.canRead(); |
length() | 获取文件大小(字节) | file.length(); |
字符流和字节流的比较表
特性 | 字节流 | 字符流 |
---|---|---|
基本类 | InputStream 和 OutputStream | Reader 和 Writer |
数据处理单位 | 字节(8位) | 字符(16位) |
适用场景 | 二进制数据(如图像、音频) | 文本数据(如文本文件) |
典型实现类 | FileInputStream , FileOutputStream | FileReader , FileWriter |
序列化与反序列化的表格总结
概念 | 描述 | 示例 |
---|---|---|
序列化 | 将对象转换为字节流并写到文件或网络中 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("file.ser")); oos.writeObject(object); |
反序列化 | 将字节流转换为对象 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file.ser")); Object obj = ois.readObject(); |
必需接口 | 需要实现 Serializable 接口 | class Person implements Serializable { ... } |
序列化ID | 建议定义 serialVersionUID 字段以避免反序列化不兼容 | private static final long serialVersionUID = 1L; |
NIO关键概念表格总结
概念 | 描述 | 示例 |
---|---|---|
缓冲区(Buffer) | 用于存储数据的容器,可以是字节、字符、短整型等 | ByteBuffer buffer = ByteBuffer.allocate(10); |
通道(Channel) | 用于连接数据源与缓冲区,实现I/O操作 | FileChannel.open(path, StandardOpenOption.READ); |
选择器(Selector) | 用于管理多个通道,实现非阻塞I/O的多路复用 | Selector.open(); selector.select(); |
总结
本文详细介绍了Java I/O操作,包括文件和目录操作、字符流与字节流的区别、序列化与反序列化、新的I/O(NIO)等内容。通过示例代码和表格总结,帮助您更好地理解和应用Java中的I/O操作,提高程序的读取和写入效率。