从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

    • 我的 Java 学习路线
    • 安装 Java
    • Java数据类型

    • Java 多版本配置
    • 面向对象

    • Java核心类

    • IO

      • IO 介绍
      • File 对象介绍
      • InputStream
        • read 方法介绍
        • read 方法实践
        • try(resource)
        • 缓冲
        • 阻塞
        • ByteArrayInputStream
        • 小结
      • OutputStream
      • Decorator 模式
      • 读写 zip 文件
      • Properties 类
      • 读取 classpath 中的配置文件
      • 序列化与反序列化
      • Reader
      • Writer
      • PrintStream 和 PrintWriter
      • Scanner
      • 使用 Files
      • Console
      • IO 系列小结
    • Java与时间

    • 异常处理

    • 哈希和加密算法

    • Java8新特性

    • 网络编程

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSE
  • IO
2023-02-02
目录

InputStream

# InputStream

InputStream 是 Java 标准库提供的最基本的输入流,它是一个抽象类,是所有输入流的超类。

类的定义如下

public abstract class InputStream implements Closeable
1

# read 方法介绍

InputStream 最重要的方法就是 int read(),签名如下:

public abstract int read() throws IOException;
1

这个方法会读取输入流的下一个字节,并返回字节表示的 int 值(0~255)。如果已读到末尾,返回 -1 表示不能继续读取了。

在计算机中,类似文件、网络端口这些资源,都是由操作系统统一管理的。应用程序在运行的过程中,如果打开了一个文件进行读写,完成后要及时地关闭,以便让操作系统把资源释放掉,否则,应用程序占用的资源会越来越多,不但白白占用内存,还会影响其他应用程序的运行。

InputStream 和 OutputStream 都是通过 close() 方法来关闭流。关闭流就会释放对应的底层资源。

为了避免程序异常导致没有关闭流,我们可以用 try ... finally。

# read 方法实践

我们来实践下,逐个读取一个文件的字节,这里我们用 FileInputStream,它是 InputStream 的一个子类,用于从文件流中读取数据。

首先创建一个 readme.txt 文件,里面写上内容 AAA

然后编写代码读取并打印:

import java.io.FileInputStream;
import java.io.InputStream;

public class IODemo5FileInputStream {
  public static void main(String[] args) {
    InputStream input = null;
    int n;
    try {
      input = new FileInputStream("readme.txt");
      while (-1 != (n = input.read())) {
        System.out.println(n);
      }
    } finally {
      if(null != input)
        input.close();
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

输出结果:65 65 65 (就是 A 的 ASCII 码)

# try(resource)

用 try ... finally 看起来代码有点复复杂,Java7 引入了 try(resource) 的语法,只需要编写 try 语句,让编译器自动为我们关闭资源:

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

public class IODemo5FileInputStream2 {
  public static void main(String[] args) throws IOException {
    try (InputStream input = new FileInputStream("readme.txt")) {
      int n;
      while( -1 != (n = input.read())){
        System.out.println(n);
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

实际上,编译器并不会特别地为 InputStream 加上自动关闭。编译器只看 try(resource = ...) 中的对象是否实现了 java.lang.AutoCloseable 接口,如果实现了,就自动加上 finally 语句并调用 close() 方法。

虽然 InputStream 和 OutputStream 实现的是 Closeable 接口,但该接口是继承了 AutoCloseable 的,因此,都可以用在 try(resource) 中。

# 缓冲

很多流提供了一次性读取多个字节到缓冲区的功能,这样效率高。InputStream 提供了两个重载方法来支持读取多个字节。我们需要先定义一个 byte[] 数组作为缓冲区:

  • int read(byte[] b):读取若干字节并填充到 byte[] 数组,返回读取的字节数
  • int read(byte[] b, int off, int len):指定 byte[] 数组的偏移量和最大填充数

read() 方法会尽可能多地读取字节到缓冲区, 但不会超过缓冲区的大小。read() 方法的返回值不再是字节的 int 值,而是返回实际读取了多少个字节。如果返回 -1,表示没有更多的数据了。

    try (InputStream input = new FileInputStream("readme.txt")) {  
      byte[] buffer = new byte[100];
      int n = input.read(buffer);
      System.out.println(n);  //3
    }
1
2
3
4
5

# 阻塞

之前我们说过 InputStream 是同步 IO,因此在调用其相关方法的时候,我们说这些方法是阻塞(Blocking)的。

对于下面的代码:

int n;
n = input.read(); // 必须等待read()方法返回才能执行下一行代码
int m = n;
1
2
3

执行到第二行代码时,必须等 read() 方法返回后才能继续。因为读取 IO 流相比执行普通代码,速度会慢很多,因此,无法确定 read() 方法调用到底要花费多长时间。

# ByteArrayInputStream

除了用 FileInputStream 类来获取数据流,我们还可以用 ByteArrayInputStream 来在内存中模拟一个 InputStream:

    byte[] data = {114,5,14};
    try (InputStream input = new ByteArrayInputStream(data)) {  
      int n;
      while ((n = input.read()) != -1) {
          System.out.println(n);  //114,5,14
      }
    }
1
2
3
4
5
6
7

除了测试用,一般实际应用不多。

# 小结

知识点:

  • Java 标准库的 java.io.InputStream 定义了所有输入流的超类
  • FileInputStream 实现了文件流输入
  • ByteArrayInputStream 在内存中模拟一个字节流输入
  • 总是使用 try(resource) 来保证 InputStream 正确关闭
  • 声明输入流应该使用 InputStream,而不是具体的类型(例如 FileInputStream),从而使得代码可以处理 InputStream 的任意实现类
上次更新: 2024/10/3 10:01:52
File 对象介绍
OutputStream

← File 对象介绍 OutputStream→

最近更新
01
2025 年 4 月记
04-30
02
山西大同 “订婚强奸案” 将会给整个社会带来的影响有多严重? - 知乎 转载
04-26
03
一个小技巧,让电子书阅读体验翻倍!
04-18
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式