3w字一文讲透Java IO

初识 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 字节

字节流(处理二进制)

  • 核心类:InputStreamOutputStream
  • 适用:图片、音频、视频、压缩包等
  • 方法:
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);
    }
}

字符流(处理文本)

  • 核心类:ReaderWriter
  • 适用:文本文件(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 用于操作文件和目录(创建、删除、遍历等),不能直接操作文件内容 ,想读写内容,需结合 输入输出流 (如 FileInputStreamFileWriter 等)。

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
  • 相对路径 :相对于当前工作目录,如
    "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 中,OutputStreamInputStream 是所有字节输出流/输入流的抽象父类。

字节输出流

基本定义

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
  • 文件复制实质是:读入字节 → 写出字节 → 关闭流
相关推荐
nianniannnn3 小时前
Qt布局管理停靠窗口QDockWidget类
开发语言·数据库·c++·qt·qt5·qt6.3
Yeats_Liao3 小时前
Go Web 编程快速入门 07.4 - 模板(4):组合模板与逻辑控制
开发语言·后端·golang
木易 士心3 小时前
MyBatis 与 Spring Data JPA 核心对比:选型指南与最佳实践
java·spring·1024程序员节
努力写代码的熊大3 小时前
stack、queue与priority_queue的用法解析与模拟实现
java·前端·javascript
lightqjx3 小时前
【C++】list 常见使用和模拟实现
开发语言·c++
ceclar1234 小时前
C++容器queue
开发语言·c++
陈皮话梅糖@4 小时前
Speckit和Claude 的初体验
开发语言·ide
遥远_4 小时前
电商履约大促峰值应对:核心业务数据预热方案详解
java·spring·1024程序员节·电商大促·数据预热
屈冠成4 小时前
C语言数组:编辑世界的坚固桥梁
c语言·开发语言·算法