Java 字节流详
本文全面介绍了Java字节流的使用方法,包括基础概念、核心操作和常见实现类。字节流以字节为单位处理数据,核心父类是InputStream和OutputStream,分别提供读取和写出方法。文件字节流(FileInputStream/FileOutputStream)可直接操作文件,缓冲字节流(BufferedInputStream/BufferedOutputStream)通过缓冲区提高IO效率,
Java 字节流
在 Java 的 IO 体系中,字节流是处理数据的核心工具之一。无论是文本文件、图片还是音频,都可以通过字节流进行读写操作。本文将详细介绍 Java 字节流的基础知识、核心方法、常用实现类以及实战中的注意事项,帮助你更好地理解和使用字节流。
一、字节流概述
字节流是 Java IO 体系中以字节为单位处理数据的流,适用于所有类型的数据(文本、图片、音频等)。字节流的顶级抽象父类是 InputStream
和 OutputStream
,分别用于定义数据读取和写出的基本方法。
1.1 字节流的特点
-
字节为单位:字节流以字节为单位处理数据,即使是文本数据也会先转换为字节序列。
-
编码问题:处理汉字等字符时,字节数并不固定,取决于具体的编码方式(如 UTF-8 编码中一个汉字通常占 3 个字节,GBK 编码中通常占 2 个字节)。
二、字节流核心方法
2.1 InputStream(字节输入流)核心方法
表格
复制
方法 | 描述 | 易错点 |
---|---|---|
int read() |
读取 1 个字节,返回 0-255 的整数;返回-1 表示读取结束(EOF) |
忘记判断-1 会导致死循环或读取错误数据 |
int read(byte[] b) |
读取字节到数组b 中,返回实际读取的字节数(最多b.length );返回-1 表示结束 |
直接用b 转换字符串时,未考虑 "读不满数组" 的情况 |
int read(byte[] b, int off, int len) |
从off 位置开始存储,最多读len 个字节,返回实际读取数 |
off 越界或len 超过数组剩余空间会抛异常 |
void close() |
关闭流,释放资源 | 忘记关闭会导致资源泄露 |
long skip(long n) |
跳过n 个字节,返回实际跳过的字节数 |
不能保证完全跳过n 个字节(如到文件末尾) |
2.2 OutputStream(字节输出流)核心方法
表格
复制
方法 | 描述 | 易错点 |
---|---|---|
void write(int b) |
写出 1 个字节(只取b 的低 8 位) |
直接写字符 ASCII 码时,需注意编码匹配 |
void write(byte[] b) |
写出数组b 中所有字节 |
数组为null 会抛NullPointerException |
void write(byte[] b, int off, int len) |
从off 开始,写出len 个字节 |
len 超过数组长度会抛异常 |
void close() |
关闭流 | 未关闭可能导致数据未完全写出(缓冲流场景) |
void flush() |
强制写出缓冲区数据(子类实现) | 缓冲流未调用flush 可能导致数据滞留缓冲区 |
2.3 流对象的声明与关闭机制
为了确保资源安全释放,建议将流对象的声明提级并初始化为null
,在try
块中创建流实例,在finally
块中判断流不为null
后关闭。这种方式可以避免因流对象未初始化而导致的空指针异常,是显式关闭流以避免资源泄露的安全实践。
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\test.txt");
// 读取数据
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、常用字节流实现类
3.1 文件字节流(节点流)
文件字节流是直接操作文件的字节流,属于节点流(低级流)。
3.1.1 FileInputStream(文件字节输入流)
-
作用:从文件中读取字节数据。
-
构造器:
-
FileInputStream(String path)
:通过文件路径创建。 -
FileInputStream(File file)
:通过File
对象创建。
-
-
示例代码:
try (FileInputStream fis = new FileInputStream("D:\\test.txt")) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
-
注意事项:
-
输入流的作用是读取数据,不能创建文件。如果尝试读取一个不存在的文件,会抛出
FileNotFoundException
。 -
转换为字符串时必须指定实际读取的长度范围,否则会包含数组中未覆盖的旧数据。
-
3.1.2 FileOutputStream(文件字节输出流)
-
作用:向文件中写出字节数据。
-
构造器:
-
FileOutputStream(String path)
:覆盖原有内容。 -
FileOutputStream(String path, boolean append)
:append=true
时追加内容。
-
-
示例代码:
-
try (FileOutputStream fos = new FileOutputStream("D:\\test.txt", true)) { fos.write("Hello".getBytes()); fos.write(10); // 写出换行符(ASCII码10) } catch (IOException e) { e.printStackTrace(); }
-
注意事项:
-
输出流会自动创建不存在的文件,但不会创建不存在的文件夹。
-
未指定
append=true
时,写入会覆盖原有内容,需谨慎操作。
-
-
3.2 缓冲字节流(处理流)
缓冲流是处理流(高级流),通过内部缓冲区减少 IO 次数,提高读写效率。
3.2.1 缓冲区工作原理
-
输入缓冲(BufferedInputStream): 内部维护一个缓冲区(默认 8192 字节),首次读取时,会一次性从文件读取尽可能多的数据存入缓冲区;程序读取数据时,先从缓冲区获取,当缓冲区里的数据被拿完后,缓冲流会再次一次性读取数据存储到缓冲区,反复循环,直到文件数据读完。
-
输出缓冲(BufferedOutputStream): 写入数据时先存入缓冲区,当缓冲区满、调用
flush()
或close()
时,才将数据一次性写入文件。 -
3.2.2 代码示例
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("D:\\test.txt")
)) {
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("D:\\test.txt")
)) {
bos.write("Hello Buffer".getBytes());
bos.flush(); // 强制写出缓冲区(即使未满)
} catch (IOException e) {
e.printStackTrace();
}
-
注意事项:
-
缓冲输出流未调用
flush()
或close()
时,数据可能滞留缓冲区,导致文件内容不完整。 -
关闭流时,只需关闭缓冲流(处理流),底层节点流会被自动关闭。
-
3.3 数据字节流(处理流)
数据字节流提供基本数据类型的读写方法(如int
、double
),确保数据按原始类型存储和读取。
3.3.1 核心方法
-
DataOutputStream:
writeInt()
、writeDouble()
、writeUTF()
等。 -
DataInputStream:
readInt()
、readDouble()
、readUTF()
等。
3.3.2 代码示例
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("D:\\data.txt")
)) {
dos.writeInt(2023);
dos.writeDouble(3.14);
dos.writeUTF("Java IO");
} catch (IOException e) {
e.printStackTrace();
}
try (DataInputStream dis = new DataInputStream(
new FileInputStream("D:\\
更多推荐
所有评论(0)