教程中心 / Java教程 / 字节流

字节流

15分钟 I/O流

什么是字节流?

字节流是Java I/O中最基本的流,以字节(byte)为单位进行数据读写。所有数据本质上都是二进制字节,所以字节流可以处理任何类型的数据——图片、音频、视频、可执行文件等。

生活比喻

字节流就像水管,只能传输水(字节)。无论你传输的是纯净水(文本)还是汤(图片/视频),都只能以水分子(字节)的形式通过。字符流则像是专门设计的饮料管,有不同的处理方式来保持饮料的特性。

字节流家族体系

InputStream(输入字节流)
    │
    ├── FileInputStream        ← 文件输入流
    ├── BufferedInputStream    ← 带缓冲,提高效率
    ├── ByteArrayInputStream   ← 字节数组输入
    ├── ObjectInputStream      ← 对象输入流(反序列化)
    └── FilterInputStream      ← 装饰器基类

OutputStream(输出字节流)
    │
    ├── FileOutputStream       ← 文件输出流
    ├── BufferedOutputStream   ← 带缓冲
    ├── ByteArrayOutputStream  ← 字节数组输出
    └── ObjectOutputStream     ← 对象输出流(序列化)

FileInputStream - 读取文件

import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamDemo {
    public static void main(String[] args) {
        String path = "test.txt";

        // 方法1:一个字节一个字节读(效率低)
        System.out.println("===== 单字节读取 =====");
        try (FileInputStream fis = new FileInputStream(path)) {
            int data;
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 方法2:批量读取到字节数组(效率高)
        System.out.println("\n\n===== 批量读取 =====");
        try (FileInputStream fis = new FileInputStream(path)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                String content = new String(buffer, 0, bytesRead);
                System.out.print(content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileOutputStream - 写入文件

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo {
    public static void main(String[] args) {
        String path = "output.txt";

        // 写入字符串
        System.out.println("===== 写入文件 =====");
        try (FileOutputStream fos = new FileOutputStream(path)) {
            String text = "Hello, Java IO!\n这是第二行。";
            fos.write(text.getBytes());  // 将字符串转为字节数组写入
            System.out.println("写入成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 追加模式写入
        System.out.println("===== 追加写入 =====");
        try (FileOutputStream fos = new FileOutputStream(path, true)) {
            String append = "\n这是追加的内容。";
            fos.write(append.getBytes());
            System.out.println("追加成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedInputStream/BufferedOutputStream - 缓冲流

缓冲流是装饰器模式的应用,它在内部维护一个缓冲区,减少实际的I/O操作次数,显著提高性能。

import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) {
        String source = "source.txt";
        String dest = "dest.txt";

        // 使用缓冲流复制文件
        System.out.println("===== 缓冲流文件复制 =====");
        long start = System.currentTimeMillis();

        try (
            BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(source));
            BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(dest))
        ) {
            byte[] buffer = new byte[8192];  // 8KB缓冲区
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            System.out.println("复制完成!");
        } catch (IOException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("耗时: " + (end - start) + "ms");
    }
}

为什么需要缓冲流?

对比项无缓冲有缓冲
每次read()调用一次系统read()从内存缓冲区读取
磁盘访问每次读写都访问缓冲区满才访问
性能
适用场景小文件、随机访问大文件、顺序读写

文件复制完整示例

import java.io.*;

public class FileCopyDemo {
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("用法: java FileCopy <源文件> <目标文件>");
            return;
        }

        String source = args[0];
        String dest = args[1];

        System.out.println("源文件: " + source);
        System.out.println("目标文件: " + dest);

        long startTime = System.currentTimeMillis();

        try (
            BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(source));
            BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(dest))
        ) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            long totalBytes = 0;

            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
            }

            long endTime = System.currentTimeMillis();
            System.out.println("复制完成!");
            System.out.println("文件大小: " + totalBytes + " 字节");
            System.out.println("耗时: " + (endTime - startTime) + " ms");

        } catch (FileNotFoundException e) {
            System.out.println("文件不存在: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("I/O错误: " + e.getMessage());
        }
    }
}

ByteArrayInputStream/ByteArrayOutputStream

字节数组流用于在内存中进行I/O操作,不需要关闭。

import java.io.*;

public class ByteArrayStreamDemo {
    public static void main(String[] args) {
        // 写入字节数组
        System.out.println("===== 字节数组输出 =====");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        String text = "Hello, ByteArrayStream!";
        baos.write(text.getBytes());
        byte[] data = baos.toByteArray();
        System.out.println("写入的字节数组: " + new String(data));

        // 从字节数组读取
        System.out.println("\n===== 字节数组输入 =====");
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        int b;
        while ((b = bais.read()) != -1) {
            System.out.print((char) b);
        }
        System.out.println();
    }
}

小结

  • 字节流以字节为单位处理所有二进制数据
  • InputStream是输入字节流的抽象基类
  • OutputStream是输出字节流的抽象基类
  • FileInputStream/FileOutputStream用于文件读写
  • Bufferedxxx缓冲流提高I/O效率,应优先使用
  • 使用try-with-resources确保流正确关闭
☕ Java 在线代码编辑器
📝 运行结果