<JavaEE> 文件IO -- 数据流和文件内容操作(Reader 和 Writer 、InputStream 和 OutputStream)

目录

一、数据流概述

二、流的关闭

2.1 使用 close() 方法

2.2 使用 try-finally

2.3 使用 try-with-resources

三、字符流的读写

3.1 Reader 类

3.2 Writer 类

四、字节流的读写

4.1 InputStream 类

4.2 OutputStream 类


一、数据流概述

1)在 Java 中,文件的操作分为两类
操作文件系统

通过 File 类,在系统中进行增、删、查等操作。

操作文件内容通过 数据流对象,在文件中读取或写入内容。(下文介绍该类)
2)什么是数据流?
数据流是一个抽象概念,水流可以流动,而数据也具有跟水流类似的特点,同时两者也都可以被容器容纳。
3)与文件的类型分类类似,数据流也有两种分类
字符流

文本文件是指保存合法字符的文件,字符以字符串形式保存。以字符形式传输的流对象,被称为字符流。

字节流二进制文件是指文件保存的是二进制数据。以字节形式传输的流对象,被称为字节流。
Java标准库中提供的用于读写文件的流对象有很多类,但是这些类都可以归纳到上述两个大的种类中。
4)流也分为输入流和输出流
每一个种类的流对象,都会有自己的输入流和输出流,在Java中也使用不同的类来表示。
字符流输入流类:Reader
输出流类:Writer
字节流输入流类:InputStream
输出流类:OutputStream
下文将介绍上述流对象的使用。

二、流的关闭

1)流为什么需要关闭?

这里的流是指文件的数据流,每打开一个文件,就会在内存中建立一个PCB。

PCB通过文件描述符表对这些打开的文件进行描述,不使用文件了却不关闭文件,则文件描述附表会一直被占用。

类似于内存泄漏,上述的情况就造成了文件资源泄露

文件描述符表有存储上限的,一旦没有关闭的文件超过文件描述符表的上限,就会抛出异常。

虽然 Java 有垃圾回收机制,但该机制适用于内存资源的回收。而此处泄露的是文件资源。

因此,只有在使用完毕后,关闭流,才能释放文件描述符表这样的文件资源,才不会造成文件资源泄露。

2)怎么关闭流对象?

流对象主要通过以下三种方式进行关闭:

<1>使用 close() 方法
<2>使用 try-finally
<3>使用 try-with-resources

2.1 使用 close() 方法

每个数据流的类,通常都会有一个 close() 方法,用于将这个流的对象关闭。
使用方式:直接用流对象调用 close() 方法即可。
缺点:直接用流对象调用 close() 方法固然可行,但程序如果结构复杂,极可能出现忘记调用,或虽然代码中有调用 close(),却因为代码结构问题或抛出异常问题,而无法执行到这个方法。

2.2 使用 try-finally

try-finally 语法的含义是执行 try 代码块中的代码,无论这些代码是正常执行完毕还是抛出异常,最终都必须执行 finally 代码块中的代码。

语法演示:

try{
    //创建流对象;
    //需要执行的代码;
}finally{
    流对象.close();
}

2.3 使用 try-with-resources

Java 还提供了一种更简洁明了的方式,来帮助程序员更好的管理资源。

try-with-resources 是指将使用后需要关闭的资源,在 try 关键字后使用 () 进行包裹,这样在程序运行出 try 代码块后,() 中包裹的资源将被自动释放。

语法演示:

try( //创建流对象,将需要在代码块运行完成后关闭的资源放在这里 ){
    //需要执行的代码;
}
在下文的代码演示中,将统一使用这种关闭文件资源的方式。

三、字符流的读写

字符流通过 Reader 类对数据进行读,Reader 是一种输入流。
字符流通过 Writer 类对数据进行写,Writer 是一种输出流。
Reader 类和 Writer 类都是抽象类,创建实例时需要使用他们的子类。

3.1 Reader 类

Reader 使用 read() 方法读取数据,read() 方法如果返回 -1 表示读取到文件末尾,read() 方法有以下三种方法重载
read() :无参数,一次读取一个字符。
read(char[] cbuf) :以数组为参数,最多读取 cbuf.length 字符的数据到数组中,返回实际读取的字符数量。
read(char[] cbuf, int off, int len) :以数组为参数,最多读取 cbuf.length 字符的数据到数组中,会从数组的第 off 个元素开始,将 len 长度的字符填入数组中,返回实际读取的字符数量。

代码演示使用 read() 方法:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"加油gogogo";

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try(Reader reader = new FileReader("C:/Test/A/test.txt")){
            while (true){
                //读取一个字符;
                int ch = reader.read();
                //判断是否到达文件末尾;
                if (ch == -1){
                    break;
                }
                //打印读取到的字符;
                System.out.println((char)ch);
            }
        }
    }

//运行结果:
加
油
g
o
g
o
g
o

代码演示使用 read(char[] cbuf) 方法:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"加油gogogo";

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try(Reader reader = new FileReader("C:/Test/A/test.txt")){
            while (true){
                //创建一个数组,用来存储读取到的字符;
                char[] cbuf = new char[1024];
                //将读取到的字符存入cbuf数组中,返回实际读取到的字符个数;
                int len = reader.read(cbuf);
                //判断是否到达文件末尾;
                if (len == -1){
                    break;
                }
                //打印cbuf数组中的字符;
                for (int i = 0; i < len; i++){
                    System.out.print(cbuf[i]);
                }
            }
        }
    }

//运行结果:
加油gogogo

3.2 Writer 类

Writer 使用 write() 方法写入数据,write() 方法有以下五种方法重载
write(int c) :每次写入一个字符。
write(String str) :每次写入一个字符串;
write(char[] cbuf) :每次写入多个字符;
write(String str, int off, int len) :每次写入一个字符串,从字符串中的off位置开始去写,写len长度;
write(char[] cbuf, int off, int len) :每次写入多个字符,从字符数组中的off位置开始去写,写len长度;
由于写入的数据可能保存在缓冲区,未来得及写入文件中。因此,为确保我们可以及时看到写入的内容,Writer 类提供了 flush() 方法,用于刷新缓冲区。

代码演示使用 write(int c) 方法:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"加油gogogo";

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try(Writer writer = new FileWriter("C:/Test/A/test.txt")){
            //在文件中写入对应字符串;
            writer.write("我的愿望是,世界和平!");
            //刷新缓冲区;
            writer.flush();
        }
    }

//运行结果:

打开文件 C:/Test/A/test.txt ,
发现原来的内容"加油gogogo"被替换为"我的愿望是,世界和平!"

通过上述代码,我们可以发现,原先文件中的文本内容被覆盖了。

在上述代码中,每次写入新的文本前,都会将原有的文本先清空再写入。
如果不想清空原有文本,而是在原有文本之后继续写入,则需要在打开文件时,在

 FileWriter 的构造方法的参数中填入另一个 boolean 类型的参数。当参数为 true 时,则表示追加文本。

代码演示追加文本:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"加油gogogo";

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt ,参数中添加true;
        try(Writer writer = new FileWriter("C:/Test/A/test.txt",true)){
            //在文件中写入对应字符串;
            writer.write("我的愿望是,世界和平!");
            //刷新缓冲区;
            writer.flush();
        }
    }

//运行结果:

打开文件 C:/Test/A/test.txt ,
发现内容为"加油gogogo我的愿望是,世界和平!"

四、字节流的读写

字节流通过 InputStream 类对数据进行读,InputStream 是一种输入流。
字节流通过 OutputStream 类对数据进行写,OutputStream 是一种输出流。
InputStream 类和 OutputStream 类都是抽象类,创建实例时需要使用他们的子类。

4.1 InputStream 类

InputStream 使用 read() 方法读取数据,read() 方法如果返回 -1 表示读取到文件末尾,read() 方法有以下三种方法重载
read() :无参数,一次读取一个字节。
read(byte[] b) :以数组为参数,最多读取 b.length 字节的数据到数组中,返回实际读取的字节数量。
read(byte[] cbuf, int off, int len) :以数组为参数,最多读取 b.length 字节的数据到数组中,会从数组的第 off 个元素开始,将 len 长度的字节填入数组中,返回实际读取的字节数量。

代码演示使用 read() 方法:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"abc"; 
   
    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try (InputStream is = new FileInputStream("C:/Test/A/test.txt")){
            while (true){
                //读取一个字节;
                int n = is.read();
                //判断是否到达文件末尾;
                if(n == -1){
                    break;
                }
                //打印;
                System.out.printf("%c ",n);
                System.out.println(n);
            }
        }
    }

//运行结果:
a 97
b 98
c 99

代码演示使用 read(byte[] b) 方法:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"abc"; 
   
    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try (InputStream is = new FileInputStream("C:/Test/A/test.txt")){
            while (true){
                //创建一个数组,用来存储读取到的字节;
                byte[] b = new byte[1024];
                //将读取到的字节存入b数组中,返回实际读取到的字节个数;
                int len = is.read(b);
                //判断是否到达文件末尾;
                if(len == -1){
                    break;
                }
                //打印;
                for(int i=0;i<len;i++){
                    System.out.printf("%c ",b[i]);
                    System.out.println(b[i]);
                }
            }
        }
    }

//运行结果:
a 97
b 98
c 99
根据使用的字符集的不同,一个中文字符通常会占用两到三个字节。如果我们需要从文件中读取中文字符会非常麻烦。
因此,可以使用 Scanner 类,来帮助我们从字节流结果中获取中文字符。

代码演示字节流获取中文字符的方法:

//存在当前文件,路径为"C:/Test/A/test.txt",内容为"我的愿望是,世界和平!"; 

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        //将字节流通过 Scanner 类转换为字符流,指定通过“utf8”字符集进行转换;
        try (InputStream is = new FileInputStream("C:/Test/A/test.txt");
             Scanner sc = new Scanner(is,"utf8")){
            //循环判断是否有下一行;
            while (sc.hasNext()){
                //获得下一行;
                String str = sc.next();
                //打印;
                System.out.println(str);
            }
        }
    }

//运行结果:
我的愿望是,世界和平!

4.2 OutputStream 类

OutputStream 使用 write() 方法写入数据,write() 方法有以下三种方法重载
write(int b) :每次写入一个字节。
write(char[] cbuf) :每次写入多个字节;
write(char[] cbuf, int off, int len) :每次写入多个字符,从字符数组中的off位置开始去写,写len长度;
由于写入的数据可能保存在缓冲区,未来得及写入文件中。因此,为确保我们可以及时看到写入的内容,OutputStream 类提供了 flush() 方法,用于刷新缓冲区。
由于字节流传输的是字节数据,但我们仍需要以字符形式输入,因此下文将以两种将字符转换为字节的方法分别进行演示。

代码演示使用 write(int b) 方法(以 getBytes() 转换字符的方式):

//存在当前文件,路径为"C:/Test/A/test.txt";

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try(OutputStream writer = new FileOutputStream("C:/Test/A/test.txt")){
            //需要在文件中写入的字符串;
            String str = "我的愿望是,世界和平!";
            //将字符转换为字节并写入文件;
            writer.write(str.getBytes());
            //刷新缓冲区;
            writer.flush();
        }
    }

//运行结果:
打开文件 C:/Test/A/test.txt ,
文件内容为"我的愿望是,世界和平!"

代码演示使用 write(int b) 方法(以 PrintWriter 包裹流对象的方式):

//存在当前文件,路径为"C:/Test/A/test.txt";

    public static void main(String[] args) throws IOException {
        //打开文件C:/Test/A/test.txt;
        try(OutputStream writer = new FileOutputStream("C:/Test/A/test.txt")){
            //使用PrintWriter类将输入的字符自动转换为字节;
            PrintWriter printWriter = new PrintWriter(writer);
            //写入文件;
            printWriter.write("我的愿望是,世界和平!");
            //刷新缓冲区;
            writer.flush();
        }
    }

//运行结果:
打开文件 C:/Test/A/test.txt ,
文件内容为"我的愿望是,世界和平!"

阅读指针 -> 《网络编程》

链接生成中........

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

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

相关文章

为什么QLC NAND才是ZNS SSD最大的赢家?-part3

在ZNS SSD设计中&#xff0c;也有很多的挑战&#xff1a; Open Zones 对写入缓冲区的需求&#xff1a;保持大量的 open zones&#xff08;例如 1K&#xff09;会增加对带宽的需求&#xff0c;并要求控制器提供足够的缓冲空间来管理并发写入请求。这需要较大的高带宽写入缓冲区以…

DENet:用于可见水印去除的Disentangled Embedding网络笔记

1 Title DENet: Disentangled Embedding Network for Visible Watermark Removal&#xff08;Ruizhou Sun、Yukun Su、Qingyao Wu&#xff09;[AAAI2023 Oral] 2 Conclusion This paper propose a novel contrastive learning mechanism to disentangle the high-level embedd…

ELK简单介绍一

任务背景 运维人员需要对系统和业务日志进行精准把控&#xff0c;便于分析系统和业务状态。日志分布在不同的服务器上&#xff0c;传统的使用传统的方法依次登录每台服务器查看日志&#xff0c;既繁琐又效率低下。所以我们需要集中化的日志管理工具将位于不同服务器上的日志收…

前端反向代理的神奇世界:加速、安全与缓存的秘密(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

3D Font

在游戏中使用3D文本 只需添加预制件并立即生成您的文本。 特点: *真实3D字母&#xff0c;可用作游戏对象*移动友好低聚 *VR兼容 *WebGL兼容 *30种以上不同字体 *材料和颜色可定制 WebGL演示 https://indiechest.itch.io/3d-font-engine 下载&#xff1a; ​​Unity资源商店链…

【lesson13】MySQL表的基本操作之create(创建),update(更新)和replace(替换)

文章目录 表的增删查改create测试建表基础测试 update测试建表基础测试 replace&#xff08;替换&#xff09;测试建表基础测试 表的增删查改 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; create 测试 建表…

opencl.dll如何修复?快速解决opencl.dll缺失总共有5种方案

在计算机使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“opencl.dll缺失”。OpenCL&#xff08;Open Computing Language&#xff09;是一种开放的并行计算框架&#xff0c;用于编写高性能的并行程序。当opencl.dll文件丢失或损坏时&#xff0c;可…

Simple Water Caustic Pattern In Unity ShaderGpaph

shadertoy上有各种神奇的效果&#xff0c;以我的见识根本想象不到这些是怎么弄出来的。 不过不会做至少可以先会用。 这篇文章抓取一个shadertoy的示例以制作一个测试效果。 参考这篇shadertoy&#xff0c;使用自定义节点装填hlsl的noise代码 Shader - Shadertoy BETA 首先使…

生物芯片市场分析:预计2029年将达到180亿美元

生物芯片(biochip或bioarray)是根据生物分子间特异相互作用的原理&#xff0c;将生化分析过程集成于芯片表面&#xff0c;从而实现对DNA、RNA、多肽、蛋白质以及其他生物成分的高通量快速检测。狭义的生物芯片概念是指通过不同方法将生物分子(寡核苷酸、cDNA、genomic DNA、多肽…

Vue之Computed(计算属性)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

Linux的五种IO模型

众所周知&#xff0c;出于对 OS 安全性的考虑&#xff0c;用户进程是不能直接操作 I/O 设备的。必须通过系统调用请求操作系统内核来协助完成 I/O 动作。 下图展示了 Linux I/O 的过程。 操作系统内核收到用户进程发起的请求后&#xff0c;从 I/O 设备读取数据到 kernel buff…

复旦微用AXIDMA接收原始图像

参考SD卡移植博客&#xff0c;&#xff0c;移植SD卡相应代码 AXIDMA部分Demo下的bsp包整个pl搬到相应位置&#xff0c;添加相应文件 #include <stdio.h> #include <stdlib.h> #include "platform.h" #include "fmsh_common.h" #include "…

算法中的最优化方法课程复习

算法中的最优化方法课程复习 单模函数、拟凸函数、凸函数证明证明一个线性函数与一个凸函数的和也是凸的 梯度线性规划标准形式以及如何标准化标准形式常见标准化方法线性化技巧 单纯形法二次规划无约束优化Nelder-Mead线搜索FR共轭梯度法例题 优化算法的选择、停止准则算法选择…

echarts 没画出来图形,dom报错宽高未识别

当echarts 刷新时&#xff0c;画不出图形 控制台 报错 应当是你画布&#xff0c;父级使用了flex布局&#xff0c;找成了画布的宽高失效 解决方法&#xff1a;画布class上加上一句 flex-shrink: 0;

算法笔记—链表、队列和栈

链表、队列和栈 1. 链表1.1 单链表反转1.2 双链表反转1.3 合并两个有序链表1.4 链表相加1.5 划分链表 2. 队列和栈2.1 循环队列2.2 栈实现队列2.3 队列实现栈2.4 最小栈2.2 双端队列 1. 链表 1.1 单链表反转 力扣 反转链表 // 反转单链表public ListNode reverseList(ListNod…

三、Shell 环境

一、Linux 系统分类 在 Linux 中&#xff0c;常见的 Shell 有以下几种&#xff1a; Bourne Shell&#xff08;sh&#xff09;&#xff1a;最早的 Shell&#xff0c;由 Stephen Bourne 开发。它是大多数其他 Shell 的基础。Bourne Again Shell&#xff08;bash&#xff09;&am…

螺旋矩阵算法(leetcode第59题)

题目描述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。示例 1&#xff1a;输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]] 示例 2&#xff1a;输入&#…

SQL Server 远程连接服务器数据库

本文解决sql server的远程连接问题。需要开启防火墙&#xff0c;开启端口&#xff0c;并处理权限不足的报错: 【use 某数据库】The server principal "[server]" is not able to access the database "[database]" under the current security context. 【…

[C/C++]——内存管理

学习C/C的内存管理 前言&#xff1a;一、C/C的内存分布二、C语言中动态内存管理方式三、C中动态内存管理方式3.1、new/delete操作符3.1.2、new/delete操作内置类型3.1.3、new/delete操作自定义类型 3.2、认识operator new和operator delete函数3.3、了解new和delete的实现原理3…

json.loads和eval 速度对比

json.loads和eval 速度对比 代码1结果图代码2参考地址 代码1 import json import time import pandas as pddata_sets pd.read_pickle("val_token_id.pandas_pickle") data_sets[str(i) for i in data_sets] starttime.time() [json.loads(i) for i in data_sets] …