[Java EE] 文件IO (二):文件内容读写-----数据流

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(94平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

    • 2.2 数据流-----文件内容读写
      • 2.2.1 字节流
        • 2.2.1.1 InputStream概述
        • 2.2.1.2 FileInputStream概述
        • 2.2.1.3 利用Scanner进行字符读取
        • 2.2.1.4 OutputStream概述
        • 2.2.1.5 FileOutputStream概述
      • 2.2.2 字符流
        • 2.2.2.1 Reader
        • 2.2.2.2 Writer

2.2 数据流-----文件内容读写

文件内容读写的操作中常见的包含以下操作:读文件,写文件,打开文件,关闭文件.
Java中通过"流"这样的一组类进行上述的文件操作.
Java中常见的流分为一下两类:字节流和字符流

  • 字节流:以字节为单位进行读写,包括以下两个类,InputStream和OutputStream.
  • 字符流:以字符为单位进行读写,包括以下两个类,Reader和Writer.
    字节流和字符流后面的用法基本上一样,核心操作就是read读,write写.close关闭.

举例说明:水流
在这里插入图片描述
接水和放水的方式有好几种,可以一次性全部放(取)完,也可以分为多次放(取),文件的读写操作也是同样的道理.

文件的读写可以一次性读取完全部的内容,也可以规定一次性读取的字节数.

2.2.1 字节流

字节流这里读取的文件可以是二进制文件,也可以是文本文件

2.2.1.1 InputStream概述

方法:

修饰符及返回值类型⽅法签名说明
intread()读取⼀个字节的数据,返回-1代表已经完全读完了
intread(byte[] b)最多读取b.length字节的数据到b中,返回实际读到的数量;-1代表以及读完了
intread(byte[] b,int off,int len)最多读取len-off字节的数据到b中,放在从off开始,返回实际读到的数量;-1代表以及读完了
voidclose()关闭字节流

[注意事项]

  • 第二个read方法中给出了一个字节数组,代表的是,我们需要先准备好一个空数组,方法执行完毕之后,就会把读取到的数据填写到byte数组中,其中初始化byte数组的时候,可以指定一次性读取的字节数.也就是说,一次性读取字节数的多少取决于数组的长度,read会尽可能填满数组,如果填不满,能填多少填多少.

举例说明:取食堂打饭
取食堂打饭的时候,我们会先拿上一个空盘子,也就是固定大小的空数组,之后我们把这个盘子递给食堂的阿姨,也就是把空数组递给read方法,但是这里的食堂的阿姨不一样,这里的食堂阿姨不会手抖,会尽可能地把整个盘子都给你打满,如果剩下的饭不多了,食堂阿姨也没有办法,只能把盆子里剩下的所有的饭都给你打上,你也只能吃锅底了.(填不满,能填多少填多少)
在这里插入图片描述

  • 我们看到,前三个方法读取的时候,读取的应该是字节流,但是我们返回值的类型却是int类型,这是为什么呢?
    • 首先,在我们读到文件结束位置的时候,会返回-1,为了有余地表示-1,所以用int.
    • 可以确保杜处的字节,都是正数,都是按"无符号"的方式处理的.
  • 需要注意的是,我们在最后必须要关闭流,否则出现不可预知的bug.
  • InputStream只是一个抽象类,要使用的时候,还得有具体的类去实现.关于InputStream的实现类有很多,基本可以认为不同的输⼊设备都可以对应⼀个InputStream类,(包括蓝牙输入,网卡输入,硬盘输入)我们现在只关⼼从硬盘中读取,所以使用FileInputStream.
2.2.1.2 FileInputStream概述

构造方法:

签名说明
FileInputStream(File file)利⽤File构造⽂件输⼊流
FileInputStream(String name)利⽤⽂件路径构造⽂件输⼊流

第一个构造方法传入的是File对象,也就是通过File类提前创建好的文件对象来构造文件输入流.
第二个方法是通过传入文件的绝对路径或者是相对路径来构造文件输入流.

代码示例:输入效率问题

    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        file.createNewFile();
        try(OutputStream outputStream = new FileOutputStream("./test.txt")){
            byte[] array = {(byte) 'a',(byte)'b',(byte)'c',(byte)'d'};//注意强制类型转换
            outputStream.write(array);
            outputStream.flush();
        }
        try(InputStream inputStream = new FileInputStream("./test.txt")){//使用try()的方式来保证最后数据流一定会被关闭
            byte[] array = new byte[10];//一次读取10个字节
            while (true){
                int a = inputStream.read(array);//返回实际读取到的数量
                if (a == -1){//读取到文件的末尾-1,就停止读取
                    break;
                }
                for (int i = 0; i < a; i++) {//这里之所以不写array.length是因为读到文件末尾的时候
                    //最后实际读到的字节数不一定读慢10个字节
                    System.out.println(array[i]);
                }
            }
        }
    }
public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        file.createNewFile();
        try(OutputStream outputStream = new FileOutputStream("./test.txt")){
            byte[] array = {(byte) 'a',(byte)'b',(byte)'c',(byte)'d'};//注意强制类型转换
            outputStream.write(array);
            outputStream.flush();
        }
        try(InputStream inputStream = new FileInputStream("./test.txt")){//使用try()的方式来保证最后数据流一定会被关闭
            while (true){
                int a = inputStream.read();//返回实际读取到的数量
                if (a == -1){//读取到文件的末尾-1,就停止读取
                    break;
                }
                System.out.println((char) a);
            }
        }
    }

注:OutputStream先不用管,我们先看InputStream的方法.

  • 第一种模式读取数据是每次读取10个字节的数据,但是第二个就是每次读取1个字节的数据.这两种方法相比,第一种方法的效率相对较高,是应为相对第一种方法,第二种方法读取硬盘的频率相对较高,读取硬盘的操作本来就是一个非常低效的操作,所以第二种方法效率相对第一种肯定低一些.
  • 我们知道,在读取完数据之后,输入流一定要被关闭,但是为了把我们的代码写得"优雅"一些,也就是不调用close方法即可关闭输入流,我们就可以把InputStream的创建放入try()中,但是可以这样做有着一定的前提条件,就是InputStream这个类实现了Closeable接口.
    public abstract class InputStream implements Closeable
2.2.1.3 利用Scanner进行字符读取

上述例子中,我们看到了对字符类型直接使用InputStream进行读取是非常麻烦且困难的,所以,我
们使用⼀种我们之前比较熟悉的类来完成该⼯作,就是Scanner类

构造⽅法说明
Scanner(InputStream is, String charset)使⽤charset字符集进行is的扫描读取

从上述Scanner的构造方法中,我们看到,Scanner的其中一个构造方法中,有一个参数就是输入流类型的参数.也就是说,我们在之前使用idea的控制台输入的一些内容,其实本质上就是一种输入流类型的数据.

public static void main7(String[] args) throws IOException {
        try(InputStream inputStream = new FileInputStream("./test.txt")){
            //之所以把Scanner放在try中,是因为最后它也要关闭
            try(Scanner scanner = new Scanner(inputStream)) {//这里Scanner传入的对象是一个输入流对象
                while (scanner.hasNext()){
                    System.out.println(scanner.next());
                }
            }
        }
    }
2.2.1.4 OutputStream概述

方法:

修饰符及返回值类型⽅法签名说明
voidwrite(int b)写⼊要给字节的数据
voidwrite(byte[] b)将b这个字符数组中的数据全部写⼊os中
intwrite(byte[] b,int off,int len)将b这个字符数组中从off开始的数据写⼊os中,⼀共写len个
voidclose()关闭字节流
voidflush()重要:我们知道I/O的速度是很慢的,所以,⼤多的OutputStream为了减少设备操作的次数,在写数据的时候都会将数据先暂时写⼊内存的⼀个指定区域⾥,直到该区域满了或者其他指定条件时才真正将数据写⼊设备中,这个区域⼀般称为缓冲区。但造成⼀个结果,就是我们写的数据,很可能会遗留⼀部分在缓冲区中。需要在最后或者合适的位置,调⽤flush(刷新)操作,将数据刷到设备中。

[注意事项]

  • 上面方法的原理和InputStream类的方法相似,这里不再赘述.
  • OutputStream是一个抽象类,要使用具体的类来实现,现在还是只关心写的内容,所以使用FileOutStream
2.2.1.5 FileOutputStream概述

构造方法:

签名说明
FileOutputStream(File file)利⽤File构造⽂件输出流
FileOutputStream(String name)利⽤⽂件路径构造⽂件输出流

示例1:

public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("./test.txt"){
            byte[] bytes = {(byte)'a',(byte)'b',(byte)'c'};
            outputStream.write(bytes);
            outputStream.flush();
        }
    }

[注意事项]

  • 按照写方式打开文件之后,会把==文件中的内容清空,==如果不想把文件中的内容清空,这时候我们就需要给输出流的构造方法中加上一个true,表示以"追加写"的方式打开.
public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("./test.txt",true){
            byte[] bytes = {(byte)'a',(byte)'b',(byte)'c'};
            outputStream.write(bytes);
            outputStream.flush();
        }
    }
  • 如果我们在输出流中的write方法中写入的是数字,也会被ascii转化为字符.

2.2.2 字符流

字符流这里只可以读取文本文件.也就是读取的内容都是可以经过编码表编码为合法字符的.

2.2.2.1 Reader

构造方法:
Reader的构造方法和上述两个类的构造方法使用方法相同,这里不再赘述.
常用方法:
常用方法有两个,一个是read(),这个方法一次读取一个字符.一个是read(char[] cbuf),一次读取指定大小字符的字符串.
[注意事项]

  • 因为这里读取的是文本中的字符,这里常用的第二个read方法数组的类型是char[]类型,由于之前的字节流读取的是字节,所以是byte[].
  • 问题:写在文本文件中的中的如果是中文字符串,中文字符串的每一个字符是3字节,而char[]类型数组中的每一个位置是2字节,那么read(char[] cbuf)是如何做到精准读取的呢?
    解答:实际上,因为Java对上述的代码进行了编码转码,read操作在读取的时候,可以识别出String类型的每一个字符是utf-8编码格式(3字节/字),之后编译器就可以把utf-8格式的字符转码为Unicode(2字节/字)编码方式的字符.

代码演示:

public static void main10(String[] args) throws IOException {
        try(Reader reader = new FileReader("./test2.txt")){
            while (true){
                char[] chars = new char[10];
                int a = reader.read(chars);//在读取的时候,编译器会自动把汉字String中utf8的编码方式转为char中Unicode的编码方式
                //其中String中utf8编码方式是3字节,Unicode编码是2字节,char类型正好可以存下2字节
                if (a == -1){
                    break;
                }
                for (int i = 0; i < a; i++) {
                    System.out.println(chars[i]);
                }
            }
        }
    }
2.2.2.2 Writer

构造方法:略
常用方法:

方法用法
write()一次写一个字符
write(char[] cbuf)一次写多个
write(String str)一次写一个字符串

代码实例:

public static void main9(String[] args) throws IOException {
        try(Writer writer = new FileWriter("./test2.txt")){
            char[] chars = {'你','好','世','界'};
            writer.write(chars);
            writer.flush();
        }
    }

和OutputStream一样,它们在写内容的时候一样会清空文件内容,我们如果我们想重复写入,那么就要在构造方法后面加上true.

public static void main9(String[] args) throws IOException {
        try(Writer writer = new FileWriter("./test2.txt",true)){
            char[] chars = {'你','好','世','界'};
            writer.write(chars);
            writer.flush();
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/625436.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 RyTuneX 增强您的 Windows 10 和 11 体验 – Rayen Ghanmi 的首选优化器。

&#x1f4dd; 关于 RyTuneX 是使用 WinUI 3 框架构建的尖端优化器&#xff0c;旨在增强 Windows 设备&#x1f680;的性能。 RyTuneX 专为 Windows 10 和 11 打造&#xff0c;使用户能够毫不费力地删除顽固的预装应用程序并优化系统资源&#x1f6e0;️。 &#x1f680; 功能…

在线caj转换成pdf免费吗?caj变成pdf很容易!点进来!

在数字化阅读日益盛行的今天&#xff0c;各种电子文献格式层出不穷&#xff0c;其中CAJ和PDF无疑是两种最为常见的格式。CAJ是中国知网推出的一种专用全文阅读格式&#xff0c;而PDF则因其跨平台、不易被修改的特性&#xff0c;受到了广大读者的青睐。因此&#xff0c;将CAJ格式…

【Kibana】快速上手Kibana平台(KQL)

文章目录 快速使用Kibana平台常用查询语句KQL基本查询覆合查询模糊查询 目前市面上大部分的公司的日志系统都是使用ELK系统&#xff0c;因此我们进行工作必须得掌握Kibana平台的基本使用&#xff0c;这里主要说明怎么“快速使用Kibana平台”以及记录一些常用的“KQL语言”。 快…

鸿蒙内核源码分析(消息封装篇) | 剖析LiteIpc(上)进程通讯内容

基本概念 LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC&#xff08;Inter-Process Communication&#xff0c;即进程间通信&#xff09;机制&#xff0c;为轻量级进程间通信组件&#xff0c;为面向服务的系统服务框架提供进程间通信能力&#xff0c;分为内核实现和用户…

centos7中如何优雅的动态切换jdk版本?

在 CentOS 7 中动态切换 JDK 版本可以通过多种方法实现&#xff0c;其中最常见的方法是使用 alternatives 命令&#xff0c;这是 CentOS 和其他基于 Red Hat 的系统中用于管理多个软件版本的标准工具。下面我会详细介绍如何使用 alternatives 命令来切换 JDK 版本。 步骤 1: 安…

【QuikGraph】C#调用第三方库计算有向图、无向图的连通分量

QuikGraph库 项目地址&#xff1a;https://github.com/KeRNeLith/QuikGraph 相关概念 图论、连通分量、强连通分量相关概念&#xff0c;可以从其他博客中复习&#xff1a; https://blog.csdn.net/weixin_50564032/article/details/123289611 https://zhuanlan.zhihu.com/p/3…

记录Spring Boot 2.3.4.RELEASE版注解方式实现AOP和通知的执行顺序

1.advice 按照以下的顺序执行 输出结果&#xff1a;(正常和异常) 说明&#xff1a;Spring boot 2.3.4.RELEASE 版本使用的AOP是spring-aop-5.2.9.RELEASE&#xff0c;AOP的通知顺序不一样。 可以测试下Spring boot 2.1.1.RELEASE 版做对比&#xff0c;发现结果是不一样的。 2…

在React中利用Postman测试代码获取数据

文章目录 概要名词解释1、Postman2、axios 使用Postman测试API在React中获取并展示数据小结 概要 在Web开发中&#xff0c;通过API获取数据是一项常见任务。Postman是一个功能强大的工具&#xff0c;可以帮助开发者测试API&#xff0c;并查看API的响应数据。在本篇博客中&…

不懂数字后端Box List、Polygon的意思?

什么是BOX&#xff1f; 景芯SoC做design planning的第一步就是确定floorplan的box&#xff0c;也就是设计的区域。这个区域可以划分为三个边界&#xff0c;如下图所示&#xff1a; Die Box 最外面一圈&#xff0c;我们称为 Die Box&#xff0c;也就是用来放置 IO 单元&#x…

Java面试八股之String类的常用方法有哪些

Java中String类的常用方法有哪些 获取字符串信息&#xff1a; length()&#xff1a;返回字符串的字符数。 isEmpty()&#xff1a;判断字符串是否为空&#xff08;即长度为0&#xff09;。 访问单个字符&#xff1a; charAt(int index)&#xff1a;返回指定索引处的字符。 …

使用Docker创建verdaccio私服

verdaccio官网 1.Docker安装 这边以Ubuntu安装为例Ubuntu 安装Docker​&#xff0c;具体安装方式请根据自己电脑自行搜索。 2.下载verdaccio docker pull verdaccio/verdaccio3.运行verdaccio 运行容器&#xff1a; docker run -it -d --name verdaccio -p 4873:4873 ver…

29、Qt使用上下文菜单(右键菜单)

说明&#xff1a;使用四种方式实现鼠标右击界面&#xff0c;显示出菜单&#xff0c;菜单上有两个动作&#xff0c;选择两个动作&#xff0c;分别打印“111”和“222”。 界面样式如下&#xff1a; 一、方法1&#xff1a;重写鼠标事件mousePressEvent .h中的代码如下&#xff…

AIConnect 综合算力服务网络:引领智能未来,创造无限可能性!

2022年11月30日&#xff0c;由OpenAI开发的大模型聊天机器人GPT-3发布&#xff0c;首个完全意义上通过图灵测试的人工智能诞生了。这一里程碑事件的启发了人们对AI技术的发展和应用。在短短两年的时间里&#xff0c;各式各样的聊天AI&#xff0c;图片生成AI&#xff0c;视频生成…

B/S版+java开发的医院绩效考核系统maven+Visual Studio Code 医院绩效考核管理系统 提升医疗服务质量的关键

B/S版java开发的医院绩效考核系统mavenVisual Studio Code 医院绩效考核管理系统 提升医疗服务质量的关键 医院绩效评价系统的建设&#xff0c;优化医院绩效管理体系&#xff0c;规范化工作目标的设计、沟通、评价与反馈&#xff0c;改进和提供医院管理人员的管理能力和成效&am…

【强训笔记】day23

NO.1 思路&#xff1a;直接计算结果&#xff0c;先计算怪物可以抗几次攻击&#xff0c;再计算勇士受到的伤害&#xff0c;如果勇士的攻击力大于等于怪物的血量&#xff0c;那么就可以击杀无数只&#xff0c;如果勇士的血量正好是受到攻击的整数倍&#xff0c;那么击杀的怪物数…

深度解刨性能测试工具Locust

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Locust安装 …

强化训练:day8(求最小公倍数、数组中的最⻓连续⼦序列、字⺟收集)

文章目录 前言1. 最小公倍数1.1 题目描述1.2 解题思路1.3 代码实现 2. 数组中的最⻓连续⼦序列2.1 题目描述2.2 解题思路2.3 代码实现 3. 字母收集3.1 题目描述3.2 解题思路3.3 代码实现 总结 前言 1. 最小公倍数   2. 数组中的最⻓连续⼦序列   3. 字⺟收集 1. 最小公倍数…

安卓APP+TCP+服务器端

1、在.xml文件中添加权限 <uses-permission android:name"android.permission.ACCESS_WIFI_STATE"/><uses-permission android:name"android.permission.INTERNET"/>2、修改显示界面 <?xml version"1.0" encoding"utf-8&…

二叉树专题(有关二叉树的相关学习)

二叉树 1.数概念及结构 1.1树的结构 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结…

Git泄露(续)

接上一篇补充 git config --global user.name " " git config --global user.email 邮箱地址 配置用户名和邮箱 git commit 使其处于交互区&#xff0c;没有使用 -m&#xff0c;默认用vim 来编辑和提交信息 输入要提交的内容&#xff0c;然后按ESC建回到命令…