当前位置: 首页 > news >正文

字节流操作:InputStream类 读取文件的操作(三种 read 方法)

字节流操作:InputStream类 和 OutputStream类

文章目录

  • 字节流操作:InputStream类 和 OutputStream类
  • 观前提醒:
  • InputStream类 读取文件的操作(三种 read 方法)
    • 1. 不带参数的 read( )方法,返回值是:int 类型
      • 例子1(以英文字符为例):
      • 例子2(以中文字符为例):
      • 总结:
    • 2. 带 byte[ ] 参数的 read( )方法,返回值是:int
      • 此方法的注意事项:
      • 输出型参数:
      • 带 byte[ ] 参数的 read( )方法的读取演示:
    • 3. 带 三个参数的 read( )方法,返回值是:int
      • 演示:
    • 4. 读取文件的操作(三种 read方法)的简单总结
  • 总结:

观前提醒:

这篇博客是从 Java 文件操作 和 IO(3)-- Java文件内容操作(1)-- 字节流操作 这篇博客分离出来的,目的是减少博客字数。

如果你是第一次点击进来的,需要你将上面这个博客,阅读到这篇博客的连接,再点击进来看这篇文章。

InputStream类 读取文件的操作(三种 read 方法)

读取文件的最核心方法,就是:read方法

对于 InputStream类 ,Java提供了三种 read方法:

1. 不带参数的 read( )方法,返回值是:int 类型

在这里插入图片描述

这个方法的作用是:调用一次,读取一个字节

关于返回值的解释:返回的是int,不是 byte,当返回值为 -1 时,表示文件已经读取完毕

例子1(以英文字符为例):

现在在我本人的java项目路径当中,存在 test.txt 文件,文件当中,写的是 hello ,现在我使用循环,使用字节读取的方式,将里面的内容读取出来:
在这里插入图片描述
演示代码:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class demo1 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {// 读取文件操作:while (true) {int data = inputStream.read();// 返回 -1 ,说明文件内容已经读取完毕if (data == -1) {break;}System.out.println(data);}}}
}

运行结果演示:
在这里插入图片描述
相信你读到这样的结果,肯定会有疑惑:不是哥们,我文件里明明写的是 hello 啊,怎么给我输出的是 104,101… …这样的数字呢?

原因的话,就是说:我们这里是按照 字节的方式进行读取的,同时根据程序代码,是一个一个字节读取出来,分别进行打印的,而每个字节的范围,是:0 ~ 255。

hello 是由五个英文字母构成的一个英文字母在计算机中的存储大小为1个字节(byte)。所以,每个英文字母有对应的一个字节码,所以显示出来的就是五个字节码(数字)

而 hello 是纯英文的方式,是根据 ASCII码 进行编码的。我们可以查一下 ASCII码表,看看 h 在其中的表示:
在这里插入图片描述
至于其他的,你可以自己去 百度 搜查 ASCII码表,然后对照一下,运行结果中的那5个十进制数字,就正好是 hello 的对应的 ASCII码

特别提醒一下:
10 进制是正常的
8 进制是 0 开头的
16 进制是 0x 开头的

例子2(以中文字符为例):

现在在我本人的java项目路径当中,存在 test.txt 文件,文件当中,写的是 “你好” ,现在我使用循环,使用字节读取的方式,将里面的内容读取出来:
在这里插入图片描述
演示代码,还是例子1 的那个代码:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class demo1 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {// 读取文件操作:while (true) {int data = inputStream.read();// 返回 -1 ,说明文件内容已经读取完毕if (data == -1) {break;}System.out.println(data);}}}
}

运行结果:
在这里插入图片描述
这里显示的有 6 个字节,而我的文件里面写的只有 2 个汉字,所以,可以知道, 1 个汉字占 3 个字节
一个汉字占三个字节,是属于 utf-8 的编码集
我们可以看看 utf-8 的码表,去对比一下。

通过这个网站:查看字符码表 UTF-8,可以查看到 utf-8 码表中,对应汉字的字节码构成。

在码表,输入 你好 ,进行查询,结果:
在这里插入图片描述
三个字节是放到一起的,不是分开的显示,不是像我们程序当中,是分开显示的,所以,不好观察。我们可以使用 16 进制,进行打印,然后对比
十六进制,一个十六进制数字,表示 4 个 bit(比特位),两个十六进制的数字,表示 8 个bit(比特位),就是 1 个字节

那么,问题来了:Java里面,怎么打印 十六进制?
答:使用 C语言当中的 printf( )%x 或者 %X 表示的是十六进制的占位符。这两个占位符,也是有区别的。
%x小写的字母 x,表示输出出来的十六进制数中,英文字符,全部都以小写形式出现
%X大写的字母 X,表示输出出来的十六进制数中,英文字符,全部都以大写形式出现

为了与网站上查到的字符的十六进制相等,我们下面就是用 %X 来进行演示结果:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class demo1 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {// 读取文件操作:while (true) {int data = inputStream.read();// 返回 -1 ,说明文件内容已经读取完毕if (data == -1) {break;}// 以十六进制的方式,打印读取到的字节数// \n 表示的是换行符// %x 表示的是十六进制的占位符System.out.printf("%X\n",data);}}}
}

运行结果:
在这里插入图片描述
与网站上查到的十六进制编码进行比较:
在这里插入图片描述
通过对比发现,代码输出的结果的六个十六进制数字,和网上 UTF-8 编码表中,你好两个汉字所对应的十六进制数字,是一样的!!!

总结:

  1. 读取英文字符的时候,按照一个一个字节读出来的,打印的结果,是 英文字符所代表的 ASCII码
  2. 读取中文字符的时候,按照字节读取,结果以十六进制的形式表示,可以证明,是 UTF-8 字符集 中所表示的汉字

2. 带 byte[ ] 参数的 read( )方法,返回值是:int

在这里插入图片描述
这个方法的作用:调用一次,读取若干个字节读取到的数据放到定义的 字节数组 当中。

此方法的注意事项:

  1. 首先,此 read( ) 方法,带有 byte[ ] b 参数,使用之前,我们需要先定义一个这样的字节数组对象。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class demo2 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {//读取文件操作//一次读取多个字节,字节数组的长度,自行定义byte[] bytes = new byte[1024];
//            这个代码里面,有两个返回值,一个是 n,一个是 bytes数组(输出型参数)int n = inputStream.read(bytes);}}}
}

定义的这个字节数组的长度,根据自己的需要来进行自定义就可以了。

进行读操作的时候,会尽可能的把这个字节数组(字节数组的长度需要自定义)给填满,填不满的话,能填几个就是几个!

  1. 返回值,是 int 类型的数据

当返回值为 -1 时,表示文件已经读取完毕

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class demo2 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {//读取文件操作//一次读取多个字节,字节数组的长度,自行定义byte[] bytes = new byte[1024];
//            这个代码里面,有两个返回值,一个是 n,一个是 bytes数组(输出型参数)int n = inputStream.read(bytes);}}}
}

以这一句代码为例子,此处的 n 表示实际 read()方法 读取到的字节数,比如,读取了 6 个字节,n 的结果就是 6

  1. 这个read( )方法,使用 参数 作为方法的返回值,有两个返回值

第一个返回值:第二点讲到的 n (int类型的返回值)
第二个返回值:括号里面的参数,读取到的字节数据,会放到read( )方法括号里的字节数组引用指向的字节数组。

输出型参数:

这种写法,叫做“ 输出型参数 ” ,在 Java 当中,并不是很常见,在 C++ 中比较常见
什么意思呢?

不知道你们对于 Java 当中的方法(也就是 C语言 中的函数)是怎么理解的?
一般来说,我们可以把 函数/方法 想象成一座工厂参数就是原材料返回值就是产品。
在这里插入图片描述
可以根据上面这个图,对方法(也可以称为 函数)进行理解。

函数的参数,是原材料,函数的返回值,是输出的产品。
对于输出型参数来说:有的时候,我们也会使用参数来接收返回值。

在java中,如果参数是引用类型(数组,String,自定义类等),方法内部修改对象内容,能够影响到方法的外部。

在 C语言 当中,最典型的例子就是:交换两个变量的值。
如果你直接传入的是数值,形参是实参的拷贝,直接交换,就只会在方法内部生效,方法外没有影响。故而有了指针,可以传入该变量的指针,交换变量的指针所指向的值,就可以在方法外部也生效,真正实现了两个变量的值。

在Java中,没有指针了,但是有引用的概念,对于引用类型,有这么个语法特点:方法内部的修改,可以影响到方法外部 你所指向的对象。
正是由于这样的语法特点,使得引用类型的参数,可以作为输出型参数

以上,你能理解多少就理解多少,上面所述,只是扩展,哪怕你理解不了,你只需要记住:
第一个返回值:n,记录的是 read( ) 方法,这一次的读取,读到了多少个字节
第二个返回值:bytes,是数组的引用,既是参数,也是方法执行结束后,存放了读取数据的字节数组的引用。

再举一个例子:这个过程有点像 食堂打饭!!
食堂打饭,就是你拿个空的餐盘,来到窗口,你把空的餐盘递给打饭阿姨,让阿姨给你打饭,打完饭以后,餐盘给你,餐盘里面,还有饭菜。

//读取文件操作
byte[] bytes = new byte[1024];
//这个代码里面,有两个返回值,一个是 n,一个是 bytes数组(输出型参数)
int n = inputStream.read(bytes);

就拿这两句代码来进行举例:

byte[] bytes = new byte[1024];

bytes就相当于一个空餐盘

int n = inputStream.read(bytes);

inputStream.read()相当于阿姨给你打饭,你把空餐盘bytes,递给阿姨inputStream.read(bytes),打完饭后,阿姨给你的是盛满了饭菜的餐盘bytesn表示的就是你餐盘饭菜的量。

在这里插入图片描述
输出型参数的出现,本质上来说,还是语法上有限制。
Java,C++ 中,硬性要求:一个方法,只能有一个返回值,如果希望返回多个数据
(上述read()方法,就是希望同时返回,长度 和 内容数组),就只能通过引用类型的参数来凑了。

但是,同样的问题,在 Python 和 Go语言 上,就没有这样的限制了,他们都支持,一个方法,返回多个值。

带 byte[ ] 参数的 read( )方法的读取演示:

仍然是以 test.txt 文件,文件当中的 “你好” ,来进行读取打印:

具体思路:带 byte[ ] 参数的 read( )方法,可以一次读取多个字节,所以,每读一次,就需要循环遍历 bytes 数组一次,格式化输出里面的字节System.out.printf("%X\n",data),直至读取到的字节数 n 为 -1,表示文件数据已经读完,跳出 while()循环,结束读取文件操作。
这里有一个注意的点,遍历读取 bytes 数组内容的时候,不是使用 bytes.length去当作循环条件,而是使用 n,因为 n 才是真正反映此次读取到的有效字节数

演示代码:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class demo2 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {//读取文件操作byte[] bytes = new byte[1024];
//            这个代码里面,有两个返回值,一个是 n,一个是 bytes数组(输出型参数)int n = inputStream.read(bytes);
//            判断文件是否已经读取完毕if (n == -1) {break;}for (int i = 0; i <n; i++) {System.out.printf("%X\n",bytes[i]);}}}}
}

运行结果:
在这里插入图片描述
这里显示的就是 你好,所对应的 UTF-8 编码中,对应的十六进制数。

我们之前说,这个read()方法,会尽可能的去读取文件中的数据,放到你所定义的空白字节数组里面,读取到的字节数据的大小,取决于你空白字节数组的大小,现在,我们上面代码所定义的空白字节数组 bytes 的大小,由 1024 改为 3 ,同时,输出字节的时候,我们加个分隔符,以便进行区分。

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class demo2 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {//读取文件操作byte[] bytes = new byte[3];
//            这个代码里面,有两个返回值,一个是 n,一个是 bytes数组(输出型参数)int n = inputStream.read(bytes);
//            判断文件是否已经读取完毕if (n == -1) {break;}for (int i = 0; i <n; i++) {System.out.printf("%X\n",bytes[i]);}System.out.println("======================");}}}
}

运行结果:
在这里插入图片描述
所以,这个 read()方法一次能读取到多少个字节,跟你自己定义的空白字节数组的大小是有关系的。

3. 带 三个参数的 read( )方法,返回值是:int

在这里插入图片描述

对这三个参数进行解释:

byte[ ] b :就是你定义的空白字节数组,调用 read()方法,后,读取到的字节,存放到这个数组里面。

int off :off --> offset 表示的是 偏移量(数组下标),本次读取到的字节数据,从空白字节数组的 off下标 开始存放,限制存放的起始位置

int len :表示你本次读取,想读取多少个字节往空白字节数组 b 中的哪个起始位置 off开始存放,限制了你本次可以读取到的字节len 往往会和返回值的大小(本次读取到了多少个字节)是一样的。

所以这个read()方法的作用就是:想读取多少(len)个字节往空白字节数组 b 中的哪个起始位置 off下标 开始存放

这个方法的使用场景通常是:你有一个非常大的字节数组,每次读操作,都把数据放到数组的某个部分,就会使用到这个 带有三个参数的 read()方法

演示:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class demo3 {public static void main(String[] args) throws IOException {
//使用 try with resource 的语法,打开文件,并程序结束的时候,自动执行 close()方法try(InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {
//              操作文件
//              定义空白字节数组byte[] bytes = new byte[1024];//                读取文件int n = inputStream.read(bytes,0,3);
//                查看你本次读取到了多少个字节System.out.println("n = " + n);
//                判断是否已经读取结束if (n == -1) {break;}
//                输出读取后,存放到字节数组中的内容for (int i = 0; i < n; i++) {System.out.printf("%X\n",bytes[i]);}System.out.println("===================");}}}
}

运行结果:
在这里插入图片描述

代码的解释:
首先,我们还是先定义一个空白字节数组,大小为 1024个字节。

然后读取文件,使用带有三个参数的 read(bytes,0,3)方法,表示:把读取到的字节,存放到空白字节数组里面去,从字节数组的 0 下标,开始存放,同时 len 为 3,也就是,限制每一个读取的字节的数量为 3,哪怕你空白字节数组一次性能装下 1024 个字节,len 的大小,和 返回值 n 的大小是一样的,都是 3,从输出结果可以看出。

最后,当 n 等于 -1 时,表示文件已经读取完毕,结束while循环,整个java程序结束。

4. 读取文件的操作(三种 read方法)的简单总结

其实,文件内容操作,就那么几个步骤打开文件操作文件中的内容(读或者写),关闭文件

在实际开发过程当中,这三种read方法需要根据具体的情况来进行使用。

总结:

这篇博客,主要是讲解 使用字节流操作:InputStream类 读取文件的操作(三种 read 方法)。

看完这篇博客,请点击这个链接:Java 文件操作 和 IO(3)-- Java文件内容操作(1)-- 字节流操作

继续学习 OutputStream类 写数据的操作(三种 write 方法)。

最后,如果这篇博客能帮到你的,请你点点赞,有写错了,写的不好的,欢迎评论指出,谢谢!

http://www.xdnf.cn/news/717715.html

相关文章:

  • 解构产品经理
  • 深入剖析网络协议:七层协议与四层协议详解
  • 在容器里运行go程序报错:/bin/sh: ./manager: not found
  • 基于照片环境信息的AI定位技术:从原理到实战的深度解析
  • KEYSIGHT N9320B是德科技N9320B频谱分析仪
  • AVL树c++实现
  • 基于51单片机和8X8点阵屏、独立按键的射击消除类小游戏
  • matlab雷达定位仿真
  • 【请关注】关于VC++实现使用Redis不同方法,有效达到 Redis 性能优化、防击穿
  • 使用 pytesseract 构建一个简单 OCR demo
  • PostgreSQL安装
  • 【 Samba】Windows 用户访问Docker服务器上当前A用户的 ~/aaa目录
  • Kotlin中的::操作符详解
  • Android 之 kotlin 语言学习笔记二(编码标准)
  • 【DeepSeek 部署中的常见问题及解决方案】
  • [解决]在 Vue 3 使用 Vite 开发的项目中,放在 public 文件夹里的文件,在打包部署后出现 404 的问题
  • python学习打卡day39
  • IO Vs NIO
  • Sqlalchemy 连mssql坑
  • 三维可视化和实时数据处理对前端性能要求以及优化渲染效率
  • Ubuntu 和 Linux 命令行是高度通用的
  • pom.xml 文件中配置你项目中的外部 jar 包打包方式
  • 《100天精通Python——基础篇 2025 第22天:Python 多进程编程入门与实战详解》
  • 09《从依赖管理到容器化部署:Maven 全链路实战笔记,解锁 Java 项目自动化构建的终极奥秘》
  • Cancer Cell丨肺癌早期干预新突破,TIM-3靶点或成关键
  • 【Phytium】飞腾FT2000/4 GPIO功能开发实例【待完成】
  • 变量的计算
  • HarmonyOS开发:Image使用详解
  • 大数据-274 Spark MLib - 基础介绍 机器学习算法 剪枝 后剪枝 ID3 C4.5 CART
  • burpsuit抓包完整示例