从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • 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新特性

    • 网络编程

    • Java
  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

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

InputStream

# 02.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​的任意实现类
在GitHub上编辑此页 (opens new window)
上次更新: 2023/2/3 09:13:47
File对象介绍
OutputStream

← File对象介绍 OutputStream→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式