Java 字节流

在 Java 的 IO 体系中,字节流是处理数据的核心工具之一。无论是文本文件、图片还是音频,都可以通过字节流进行读写操作。本文将详细介绍 Java 字节流的基础知识、核心方法、常用实现类以及实战中的注意事项,帮助你更好地理解和使用字节流。

一、字节流概述

字节流是 Java IO 体系中以字节为单位处理数据的流,适用于所有类型的数据(文本、图片、音频等)。字节流的顶级抽象父类是 InputStreamOutputStream,分别用于定义数据读取和写出的基本方法。

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 数据字节流(处理流)

数据字节流提供基本数据类型的读写方法(如intdouble),确保数据按原始类型存储和读取。

3.3.1 核心方法
  • DataOutputStreamwriteInt()writeDouble()writeUTF()等。

  • DataInputStreamreadInt()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:\\

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐