
初识 Java IO
IO(Input / Output):指程序与外部设备之间的数据传输,如文件、网络、内存等。
Java 中使用 流(Stream) 来实现 IO 操作。
什么是流(Stream)
-
一种数据传输通道,可以顺序读取或写入数据。
-
流动方向:
- 输入流(Input Stream):数据流入程序。
- 输出流(Output Stream):数据流出程序。
-
特性:
- 先进先出(FIFO);
- 顺序访问;
- 只能单向(读或写);
- 随机访问需使用
RandomAccessFile。
按传输方式划分:字节流 vs 字符流
字节与字符的区别
| 概念 | 单位 | 示例 | 说明 |
|---|---|---|---|
| 字节(byte) | 8 位二进制 | 10101010 |
存储单位 |
| 字符(char) | 文本符号 | A、中 |
编码后由 1~3 字节表示 |
UTF-8 中:英文 1 字节,中文 3 字节
Unicode 中:英文 1 字节,中文 2 字节
字节流(处理二进制)
- 核心类:
InputStream、OutputStream - 适用:图片、音频、视频、压缩包等
- 方法:
java
int read();
int read(byte[] b, int off, int len);
void write(int b);
void write(byte[] b, int off, int len);
void flush();
void close();
示例:
java
try (FileInputStream fis = new FileInputStream("in.jpg");
FileOutputStream fos = new FileOutputStream("out.jpg")) {
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
}
字符流(处理文本)
- 核心类:
Reader、Writer - 适用:文本文件(txt、xml、java等)
- 方法:
java
int read(); //读取数据
int read(byte b[], int off, int len); //从第 off 位置开始读,读取 len 长度的字节,然后放入数组 b 中
long skip(long n); //跳过指定个数的字节
int available(); //返回可读的字节数
void close(); //关闭流,释放资源
示例:
java
try (FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt")) {
char[] buf = new char[1024];
int len;
while ((len = fr.read(buf)) != -1) {
fw.write(buf, 0, len);
}
}
02. 按操作对象划分
文件流(File)
用于直接读写文件。
java
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt", true); // 追加模式
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
文件操作:
java
File file = new File("test.txt");
file.createNewFile(); // 创建
file.delete(); // 删除
file.renameTo(new File("new.txt")); // 重命名
内存流(数组流)
在内存中读写数据,不涉及磁盘。
java
ByteArrayInputStream bais = new ByteArrayInputStream("Hello".getBytes());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("World".getBytes());
byte[] result = baos.toByteArray();
内存流容量有限,适合临时数据处理(压缩、加密等)。
管道流(Piped Stream)
实现线程间通信。
java
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
// 写线程
new Thread(() -> {
try {
pos.write("Hello Pipe".getBytes());
pos.close();
} catch (IOException e) { e.printStackTrace(); }
}).start();
// 读线程
new Thread(() -> {
try {
byte[] buf = new byte[1024];
int len = pis.read(buf);
System.out.println(new String(buf, 0, len));
pis.close();
} catch (IOException e) { e.printStackTrace(); }
}).start();
数据流(Data Stream)
读写基本数据类型。
java
// 写
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"));
dos.writeInt(123);
dos.writeDouble(45.67);
dos.close();
// 读
DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"));
int i = dis.readInt();
double d = dis.readDouble();
dis.close();
缓冲流(Buffered)
提升读写效率。
java
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
bw.flush();
br.close();
bw.close();
缓冲流内部自带缓冲区,减少系统 IO 调用次数。
打印流(Print)
打印输出各种类型数据。
java
PrintStream ps = new PrintStream(new FileOutputStream("log.txt"));
ps.println("Hello IO");
PrintWriter pw = new PrintWriter(new FileWriter("out.txt"));
pw.println("Java Writer");
pw.flush();
System.out实际上是一个PrintStream。
对象流(Object Stream)
支持对象序列化与反序列化。
java
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"));
oos.writeObject(new Person("张三", 20));
oos.close();
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"));
Person p = (Person) ois.readObject();
ois.close();
转换流(InputStreamReader / OutputStreamWriter)
桥接字节流与字符流,可指定编码。
java
InputStreamReader isr = new InputStreamReader(new FileInputStream("input.txt"), "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("output.txt"), "UTF-8");
常用于解决 编码问题(防止中文乱码)。
| 分类 | 输入流 | 输出流 | 说明 |
|---|---|---|---|
| 文件 | FileInputStream | FileOutputStream | 操作文件 |
| 字符文件 | FileReader | FileWriter | 操作文本 |
| 缓冲 | BufferedInputStream / Reader | BufferedOutputStream / Writer | 提高性能 |
| 数组 | ByteArrayInputStream | ByteArrayOutputStream | 内存数据 |
| 管道 | PipedInputStream | PipedOutputStream | 线程通信 |
| 基本类型 | DataInputStream | DataOutputStream | 读写基本类型 |
| 对象 | ObjectInputStream | ObjectOutputStream | 序列化对象 |
| 转换 | InputStreamReader | OutputStreamWriter | 字节 ⇄ 字符 |
| 打印 | - | PrintStream / PrintWriter | 便捷输出 |
字节全能,字符专文,缓冲提速,转换连桥,数据与对象更高阶,打印最常见。
文件流详解
File 类概述
java.io.File 用于操作文件和目录(创建、删除、遍历等),不能直接操作文件内容 ,想读写内容,需结合 输入输出流 (如 FileInputStream、FileWriter 等)。
File 构造方法
常用三种:
java
File(String pathname); // 通过路径名创建 File 实例
File(String parent, String child); // 通过父路径(字符串)+ 子路径
File(File parent, String child); // 通过父 File 对象 + 子路径
示例:
java
File file1 = new File("/Users/username/123.txt");
File file2 = new File("/Users/username/1", "2.txt");
File parentDir = new File("/Users/username/aaa");
File file3 = new File(parentDir, "bbb.txt");
路径分隔符推荐使用:
java
File.separator // 自动适配操作系统的分隔符
File 类使用注意事项
File对象可以表示存在或不存在的路径,构造时不会检查文件是否真实存在。- 一个
File实例代表硬盘上的一个文件或目录。
常用方法
1、 获取信息
java
getAbsolutePath(); // 返回绝对路径
getPath(); // 返回构造路径(通常与上相同)
getName(); // 文件或目录名称
length(); // 文件长度(字节数,目录时无意义)
示例:
java
File f = new File("/Users/username/aaa/bbb.java");
System.out.println(f.getAbsolutePath());
System.out.println(f.getName());
System.out.println(f.length());
2、 路径类型
-
绝对路径:从系统根目录开始,如
- Windows:
C:\Program Files\Java\jdk... - macOS/Linux:
/usr/local/bin/python3
- Windows:
-
相对路径 :相对于当前工作目录,如
"config/config.properties"
3、 判断功能
java
exists(); // 是否存在
isDirectory(); // 是否目录
isFile(); // 是否文件
示例:
java
File file = new File("/Users/username/example");
if (file.exists()) { ... }
if (file.isDirectory()) { ... }
if (file.isFile()) { ... }
4、 创建与删除
java
createNewFile(); // 创建文件,存在则返回 false
delete(); // 删除文件或空目录
mkdir(); // 创建一级目录
mkdirs(); // 创建多级目录(常用)
示例:
java
File f = new File("/Users/username/example/test.txt");
f.createNewFile();
f.delete();
File dir = new File("/Users/username/example/sub1/sub2");
dir.mkdirs();
5、 遍历目录
java
list(); // 返回子文件或目录名字符串数组
listFiles(); // 返回子文件或目录 File 对象数组
示例:
java
File dir = new File("/Users/username/Documents");
String[] names = dir.list();
for (String n : names) System.out.println(n);
File[] files = dir.listFiles();
for (File f : files) {
if (f.isFile()) System.out.println("文件:" + f.getName());
if (f.isDirectory()) System.out.println("目录:" + f.getName());
}
使用前需保证路径存在且为目录,否则可能返回 null。
6、 递归遍历目录
java
public static void traverse(File dir) {
File[] files = dir.listFiles();
if (files == null) return;
for (File f : files) {
if (f.isFile()) System.out.println("文件:" + f.getName());
else traverse(f);
}
}
RandomAccessFile
RandomAccessFile 允许在文件任意位置读写(支持"随机访问"),同时支持读与写。
构造方法
java
RandomAccessFile(File file, String mode);
RandomAccessFile(String name, String mode);
| mode | 含义 |
|---|---|
| "r" | 只读 |
| "rw" | 读写,不存在则创建 |
| "rws" | 同步更新内容与元数据 |
| "rwd" | 同步更新内容,不强制更新元数据 |
常用方法
java
long getFilePointer(); // 获取文件指针当前位置
long length(); // 文件长度
void seek(long pos); // 设置文件指针位置
int read(); // 读取一个字节
int read(byte[] b, int off, int len); // 读取字节数据
String readUTF(); // 读取 UTF-8 字符串
void write(int b); // 写入一个字节
void write(byte[] b, int off, int len); // 写入字节数组
void writeUTF(String str); // 写入 UTF-8 编码字符串
示例:写入与读取
java
File file = new File("logs/java/aicodehelper.txt");
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
raf.writeUTF("Hello, 一成在成长");
raf.seek(0);
String content = raf.readUTF();
System.out.println("内容: " + content);
}
writeUTF()与readUTF()自动写入/读取长度信息,避免乱码。
Apache Commons IO - FileUtils 类
FileUtils 是 Apache Commons IO 提供的文件工具类,封装了常见操作。
常用方法
java
FileUtils.copyFile(src, dest); // 复制文件
FileUtils.copyDirectory(src, dest); // 复制目录
FileUtils.delete(file); // 删除文件或目录
FileUtils.moveFile(src, dest); // 移动文件
FileUtils.lastModified(file); // 获取修改时间
FileUtils.sizeOf(file); // 获取大小
FileUtils.getExtension(name); // 获取文件扩展名
示例:
java
File src = new File("src.txt");
File dest = new File("dest.txt");
FileUtils.copyFile(src, dest);
Hutool 工具包 - FileUtil 类
FileUtil 是 Hutool 的文件操作工具类,封装了大量常用功能。
常用方法
java
FileUtil.copyFile(src, dest); // 复制文件
FileUtil.move(src, dest, true); // 移动文件或目录
FileUtil.del(file); // 删除文件或目录
FileUtil.rename(file, "newName.txt", true); // 重命名
FileUtil.readLines(file, "UTF-8"); // 按行读取文件
示例:
java
File file = new File("demo.txt");
File dest = FileUtil.file("backup.txt");
FileUtil.copyFile(file, dest);
FileUtil.readLines(file, "UTF-8").forEach(System.out::println);
字节流详解
- 所有文件(文本、图片、视频)在计算机中都以二进制形式存储;
- 因此,字节流可以传输任意类型文件数据;
- Java 中,
OutputStream与InputStream是所有字节输出流/输入流的抽象父类。
字节输出流
基本定义
java.io.OutputStream 是所有字节输出流的超类。
常用方法:
java
void close(); // 关闭流并释放资源
void flush(); // 刷新缓冲区(强制输出)
void write(byte[] b); // 写入整个字节数组
void write(byte[] b, int off, int len); // 从 off 开始写 len 个字节
void write(int b); // 写入单个字节(低8位生效)
FileOutputStream 类
作用:将字节数据写入文件。
构造方法
java
FileOutputStream(String name); // 通过文件名创建
FileOutputStream(File file); // 通过文件对象创建
FileOutputStream(String name, boolean append); // 可指定是否追加
FileOutputStream(File file, boolean append);
示例:
java
FileOutputStream fos = new FileOutputStream("example.txt");
fos.write("一成".getBytes());
fos.close();
写入数据的方式
(1)写单个字节
java
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write(97); // 写入 'a'
fos.write('b'); // 写入 'b'
fos.write('c'); // 写入 'c'
fos.close();
说明:
write(int b)只写入参数的 低8位 。例如
write(0x12345678)实际写入的是0x78(即'x')。
(2)写入字节数组
java
byte[] bytes = "一成在成长".getBytes();
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write(bytes);
fos.close();
(3)写入指定区间
java
byte[] data = "abcde".getBytes();
fos.write(data, 2, 2); // 从索引2开始写2个字节,即 "cd"
追加与换行
追加写入
java
FileOutputStream fos = new FileOutputStream("example.txt", true); // true 表示追加
fos.write("Hello".getBytes());
fos.close();
字节输入流(InputStream)
基本定义
java.io.InputStream 是所有字节输入流的超类。
常用方法:
java
void close(); // 关闭输入流
int read(); // 读取单个字节,返回值为 0~255;到末尾返回 -1
int read(byte[] b); // 读取多个字节到数组中
int read(byte[] b, int off, int len); // 从流中读取指定长度的字节
FileInputStream 类
作用:从文件中读取字节数据。
构造方法
java
FileInputStream(String name);
FileInputStream(File file);
若文件不存在,将抛出
FileNotFoundException。
示例:
java
FileInputStream fis = new FileInputStream("test.txt");
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
fis.close();
读取数据方式
(1)读取单个字节
java
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
(2)使用字节数组读取
java
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
fis.close();
文件复制示例(图片复制)
原理:读取 → 写入 → 关闭
java
FileInputStream fis = new FileInputStream("original.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fis.close();
fos.close();
| 抽象类 | 子类 | 功能 | 常用方法 |
|---|---|---|---|
InputStream |
FileInputStream |
从文件中读取字节数据 | read()、read(byte[]) |
OutputStream |
FileOutputStream |
将字节数据写入文件 | write(int)、write(byte[])、flush() |
| 文件复制 | --- | 读取 + 写入 | 缓冲数组循环读写 |
- 一切文件的本质都是二进制字节;
FileOutputStream→ 写文件;FileInputStream→ 读文件;write(int b)只保留低8位;- 追加写需使用构造方法的第二个参数
true; - 文件复制实质是:读入字节 → 写出字节 → 关闭流。