【Java】字节流详解
大家好,本篇继续更新 Java IO 相关内容,今天带大家系统学习Java 字节流。字节流是 IO 流中最基础也最常用的一类,专门用来处理一切二进制文件,像图片、视频、文档、普通文本都能使用字节流完成读写,也是文件复制、文件上传下载的核心基础。
一、字节流整体概述
Java 中字节流分为两大顶层抽象父类:
- 字节输出流:
java.io.OutputStream,负责把内存中的数据写出到文件/网络等目标位置 - 字节输入流:
java.io.InputStream,负责从数据源(文件、网络)读取数据到内存
两个都是抽象类,日常开发我们主要使用它们的文件专属子类:FileOutputStream(文件字节输出流)、FileInputStream(文件字节输入流)。
二、字节输出流 OutputStream & FileOutputStream
1. 顶层父类 OutputStream 核心方法
OutputStream 定义了字节输出流的通用行为,所有子类都会继承这些方法:
void close():关闭流资源,IO 流使用完毕必须关闭,释放系统资源void flush():刷新缓冲区,强制把缓冲区数据写出到目标void write(int b):写入单个字节void write(byte[] b):写入整个字节数组void write(byte[] b, int off, int len):从字节数组下标off开始,写入len个字节
2. FileOutputStream 构造方法
FileOutputStream 是文件字节输出流,专门操作本地文件,常用构造有四类:
FileOutputStream(String fileName):根据文件路径创建流,文件不存在则新建,存在则直接覆盖原内容FileOutputStream(File file):根据 File 文件对象创建流FileOutputStream(String fileName, boolean append):追加模式,append=true时在文件末尾续写,不覆盖FileOutputStream(File file, boolean append):文件对象 + 追加模式
3. 代码示例:基础写入数据
示例1:单个字节写入文件
import java.io.FileOutputStream;
import java.io.IOException;
public class OutputStreamDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建文件字节输出流,覆盖原有内容
fos = new FileOutputStream("test.txt");
// 写入单个字节
fos.write(97); // 对应字符 a
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
示例2:字节数组写入 & 分段写入
import java.io.FileOutputStream;
import java.io.IOException;
public class WriteByteArrayDemo {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("test.txt")) {
byte[] bytes = "Hello Java IO".getBytes();
// 写入整个字节数组
fos.write(bytes);
// 分段写入:从下标0开始,取5个字节
fos.write(bytes, 0, 5);
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里我使用了 JDK7+ 的try-with-resources语法,流会自动关闭,简化代码。
示例3:文件追加写入 + 换行
默认流会覆盖文件内容,如果需要续写,开启追加模式即可。
补充一点:不同系统换行符不同,Windows 是 \r\n,Linux/Mac 是 \n。
import java.io.FileOutputStream;
import java.io.IOException;
public class AppendWriteDemo {
public static void main(String[] args) {
// 第二个参数 true:开启追加模式
try (FileOutputStream fos = new FileOutputStream("test.txt", true)) {
// 换行 + 追加内容
fos.write("\r\n".getBytes());
fos.write("追加一行新内容".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、字节输入流 InputStream & FileInputStream
1. 顶层父类 InputStream 核心方法
InputStream 是所有字节输入流的抽象父类,核心方法:
void close():关闭流,释放资源int read():读取单个字节,读到文件末尾返回-1int read(byte[] b):读取数据存入字节数组,返回实际读取的字节个数,读到末尾返回-1
2. FileInputStream 构造方法
专门读取文件的字节输入流,常用构造:
FileInputStream(String name):根据文件路径创建输入流FileInputStream(File file):根据 File 对象创建输入流
注意:如果文件不存在,
FileInputStream会直接抛出文件找不到异常。
3. 代码示例:读取文件内容
示例1:单字节循环读取
逐个字节读取文件,直到返回 -1 结束:
import java.io.FileInputStream;
import java.io.IOException;
public class ReadSingleByteDemo {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt")) {
int b;
// 循环读取,b=-1 代表读取完毕
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例2:字节数组批量读取(效率更高)
单字节读取效率很低,实际开发统一使用字节数组批量读取:
import java.io.FileInputStream;
import java.io.IOException;
public class ReadByteArrayDemo {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt")) {
// 定义缓冲区数组,大小自定义
byte[] buffer = new byte[1024];
int len; // 记录每次实际读取的字节数
while ((len = fis.read(buffer)) != -1) {
// 读取多少,就转换多少
String content = new String(buffer, 0, len);
System.out.print(content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、综合实战:字节流实现文件复制
字节流最大的优势就是通用,文本、图片、视频、压缩包都能复制。下面演示一张图片的完整复制案例,也是工作中最常用的场景。
代码示例:文件复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopyDemo {
public static void main(String[] args) {
// 源文件路径、目标文件路径
String srcPath = "source.jpg";
String destPath = "copy.jpg";
try (
// 输入流:读取源文件
FileInputStream fis = new FileInputStream(srcPath);
// 输出流:写入目标文件
FileOutputStream fos = new FileOutputStream(destPath)
) {
byte[] buffer = new byte[1024];
int len;
// 边读边写
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("文件复制完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行后就能在目录下得到一份和原图完全一致的副本,这套代码可以通用在所有类型文件上。
五、内容小结
- 字节流两大抽象父类:
InputStream(输入)、OutputStream(输出),针对所有二进制数据。 - 文件专属实现类:
FileInputStream读文件,FileOutputStream写文件。 FileOutputStream默认覆盖文件,传入append=true可开启追加写入;不同系统换行符有区别。- 读写优先使用字节数组缓冲区,相比单字节读写,性能提升巨大。
- 流资源必须关闭,推荐使用
try-with-resources语法自动释放资源。 - 字节流可实现任意类型文件的复制,是 IO 基础中的重点。
以上就是 Java 字节流的全部核心知识点与实战代码,下一篇我会继续讲解字符流、缓冲流等进阶 IO 内容,感兴趣的朋友可以持续关注~


