Java IO 流详解:流的作用、流的划分与标准输入输出流

一、流的作用

在 Java 中,流(Stream)是对数据传输过程的抽象。无论是从文件读取数据、向网络发送请求,还是在内存中处理字节序列,程序都可以用统一的「流」模型来描述:数据像水流一样,从一端流向另一端。

流的核心作用可以概括为以下几点:

  • 统一数据源与数据目标:文件、内存数组、网络连接、控制台都可以抽象为流,读写代码的形态保持一致。
  • 屏蔽底层细节:调用方不需要关心数据是来自磁盘扇区还是网络报文,只需要面向流的接口编程。
  • 支持顺序读写与缓冲:流天然适合顺序处理,配合缓冲流可以显著减少系统调用次数,提升 I/O 效率。
  • 便于装饰与组合:通过装饰器模式,可以在基础流之上叠加缓冲、字符编码、对象序列化等能力,功能按需拼装。
java 复制代码
// 同一个「读」的语义,可以作用于不同数据源
InputStream fromFile = new FileInputStream("data.txt");
InputStream fromMemory = new ByteArrayInputStream("hello".getBytes());
InputStream fromNetwork = socket.getInputStream();

正是这种抽象,让 Java 的 I/O 体系具备了良好的扩展性:新增一种数据源,往往只需要实现对应的流类,而不必改动上层业务代码。

二、流的划分

Java 的流体系看似庞杂,但按照几个维度划分后,结构会非常清晰。

1. 按数据单位划分:字节流与字符流

维度 字节流 字符流
顶层抽象类 InputStream / OutputStream Reader / Writer
处理单位 字节(8 位) 字符(16 位,按编码解码)
适用场景 图片、音频、压缩包等二进制数据 文本文件、配置、日志等字符数据
典型实现 FileInputStream、BufferedInputStream FileReader、BufferedReader

字节流是最基础的,字符流本质上是在字节流之上增加了编码转换。处理文本时优先使用字符流,可以避免手动处理编码问题;处理二进制数据时必须使用字节流。

2. 按数据流向划分:输入流与输出流

  • 输入流 :从外部数据源读入程序,如 InputStream、Reader。
  • 输出流 :从程序写出到外部目标,如 OutputStream、Writer。

这里的「输入输出」是站在程序的角度定义的:数据进入程序叫输入,数据离开程序叫输出。

3. 按功能层次划分:节点流与处理流

  • 节点流 :直接连接数据源或目标,如 FileInputStream、FileOutputStream、ByteArrayInputStream。
  • 处理流 :包装在其他流之上,提供额外能力,如 BufferedInputStream(缓冲)、DataInputStream(基本类型读写)、ObjectInputStream(对象序列化)、InputStreamReader(字节转字符)。
java 复制代码
// 节点流 + 处理流的典型组合
try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(
                new FileInputStream("data.txt"), StandardCharsets.UTF_8))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}

这种分层设计让每种流只关注一件事,通过组合即可满足复杂需求。

4. 按处理方式划分:缓冲流与直接流

缓冲流在内部维护一个字节或字符数组,减少与底层设备的交互次数。对于频繁的小块读写,缓冲带来的性能提升非常明显。常见的有 BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter。

三、标准输入输出流

Java 在 System 类中预定义了三个标准流,程序启动时即可直接使用,无需手动创建。

字段 类型 含义
System.in InputStream 标准输入流,默认来自键盘
System.out PrintStream 标准输出流,默认输出到控制台
System.err PrintStream 标准错误流,默认输出到控制台

1. 标准输入流 System.in

System.in 是一个字节输入流,直接读取得到的是字节。读取文本输入时,通常需要包装成字符流。

java 复制代码
BufferedReader reader = new BufferedReader(
        new InputStreamReader(System.in, StandardCharsets.UTF_8));
String input = reader.readLine();
System.out.println("你输入的是:" + input);

也可以使用 Scanner 简化解析:

java 复制代码
Scanner scanner = new Scanner(System.in);
int number = scanner.nextInt();
String word = scanner.next();

2. 标准输出流 System.out

System.out 是 PrintStream 类型,提供了 print、println、printf 等便捷方法,并自动处理字符编码转换。

java 复制代码
System.out.println("普通输出");
System.out.printf("格式化输出:%s 的年龄是 %d%n", "张三", 20);

3. 标准错误流 System.err

System.err 用于输出错误信息,与 System.out 分离,便于在重定向时把正常输出和错误输出分别处理。

java 复制代码
try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.err.println("计算出错:" + e.getMessage());
}

4. 重定向标准流

System 提供了 setIn、setOut、setErr 方法,可以把标准流重定向到文件或其他流,这在测试和日志收集场景中很实用。

java 复制代码
try (PrintStream fileOut = new PrintStream("output.log")) {
    System.setOut(fileOut);
    System.out.println("这行内容会写入文件");
}

需要注意,重定向会影响整个 JVM 进程,使用完毕后应恢复原来的流,避免影响其他逻辑。

四、小结

流是 Java I/O 的基础抽象,它统一了不同数据源的读写方式,并通过分层与组合提供了强大的扩展能力。按数据单位可分为字节流与字符流,按方向可分为输入流与输出流,按功能层次可分为节点流与处理流。标准输入输出流则是程序与外部环境交互的最直接通道,理解它们的类型与用法,是掌握 Java I/O 的第一步。

相关推荐
lumengabc1 小时前
视频制作文字转语音PPT台词生成合成合并视频导出ffmpeg软件python edge-tts
python
MSTcheng.1 小时前
Agent 跑到一半崩了,怎么从上一步接着跑?LangGraph StateGraph 实战:状态持久化、断点恢复与人工审批
python·状态管理·ai agent·langgraph·断点恢复·人工审批
略略略咯咯1 小时前
33333
开发语言·windows·python
java_prinln1 小时前
11. 说说 Single-Agent 和 Multi-Agent 的设计方案?
python
垆边人似月.1 小时前
第三篇:函数、文件与异常处理 / Functions, Files & Exception Handling
开发语言·python
我的xiaodoujiao1 小时前
Django 权限系统项目实战详细图文教程 4--系统登录功能实现 2
后端·python·django
范同学~1 小时前
项目添加水印
java·前端·javascript
鬼手点金1 小时前
缓存作为架构约束
开发语言·前端·人工智能·python·microsoft·缓存·架构
快乐的韭菜根根1 小时前
Slurm 指定 GPU 卡:`File=/dev/nvidiaX` 映射的坑与修复
java·服务器·网络