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

本文主要是介绍<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 ,
文件内容为"我的愿望是,世界和平!"

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

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

这篇关于<JavaEE> 文件IO -- 数据流和文件内容操作(Reader 和 Writer 、InputStream 和 OutputStream)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/491792

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J