IO系列(三) - 文件读写操作介绍

一、摘要

在之前的文章中,我们了解到在 Java I/O 体系中,File 类是唯一代表磁盘文件本身的对象

File 类定义了一些与平台无关的方法来操作文件,包括检查一个文件是否存在、创建、删除文件、重命名文件、判断文件的读写权限是否存在、设置和查询文件的最近修改时间等等操作。

值得注意的地方是,Java 中通常的 File 并不代表一个真实存在的文件对象,当你通过指定一个路径描时,它就会返回一个代表这个路径相关联的一个虚拟对象,这个可能是一个真实存在的文件或者是一个包含多个文件的目录

下面我们一起来看看 File 类有哪些操作方法,以及实际使用过程中如何避坑。

二、File 类介绍

大家 JDK 中源代码,你会发现 File 类没有无参构造方法,最常用的是使用下面的构造方法来生成 File 对象。

以 windows 操作系统为例,操作文件的方式如下!

// 指定一个完整路径,获取文件对象
File file = new File("D:\\Files\\test.txt");
System.out.println(file1.getName());// 指定一个父文件路径和子文件名称,获取文件对象
File file = new File("D:\\Files", "test.txt");
System.out.println(file2.getName());

File 类中定义了很多关于 File 对象的一些操作方法,我们通过一段代码一起来看看。

public static void main(String[] args) throws Exception {// 指定一个文件完整路径,获取文件对象File file = new File("D:\\Files\\test.txt");// 获取文件父节点目录对象File parentFile = file.getParentFile();// 判断指定路径的文件目录是否存在if(parentFile.exists()){System.out.println("文件目录存在");} else {// 创建文件夹,可以自动创建多级文件夹parentFile.mkdirs();System.out.println("文件目录不存在,创建一个文件目录");}// 判断指定父节点路径的是否是一个目录if(parentFile.isDirectory()){System.out.println("父节点路径是一个目录");}// 判断指定路径的文件是否存在if(file.exists()){System.out.println("文件存在");} else {// 创建文件file.createNewFile();System.out.println("文件不存在,创建一个文件");}// 获取目录下的所有文件/文件夹(仅该层路径下)File[] files = parentFile.listFiles();System.out.print("路径下有文件:");for (File f : files) {System.out.print(f + ";");}System.out.println();// 获取文件名、文件夹名System.out.println("files[0]的文件名:" + files[0].getName());// 获取文件、文件夹路径System.out.println("files[0]的文件路径:" + files[0].getPath());// 获取文件、文件夹绝对路径System.out.println("files[0]的绝对路径:" + files[0].getAbsolutePath());// 获取文件父目录路径System.out.println("files[0]的父文件夹名:" + files[0].getParent());// 判断文件、文件夹是否存在System.out.println(files[0].exists() ? "files[0]的存在" : "files[0]的不存在");// 判断文件是否可写System.out.println(files[0].canWrite() ? "files[0]的可写" : "files[0]的不可写");// 判断文件是否可读System.out.println(files[0].canRead() ? "files[0]的可读" : "files[0]的不可读");// 判断文件是否可执行System.out.println(files[0].canExecute() ? "file[0]可执行" : "file[0]不可执行");// 判断文件、文件夹是不是目录System.out.println(files[0].isDirectory() ? "files[0]的是目录" : "files[0]的不是目录");// 判断拿文件、文件夹是不是标准文件System.out.println(files[0].isFile() ? "files[0]的是文件" : "files[0]的不是文件");// 判断路径名是不是绝对路径System.out.println(files[0].isAbsolute() ? "files[0]的路径名是绝对路径" : "files[0]的路径名不是绝对路径");// 获取文件、文件夹上一次修改时间System.out.println("files[0]的最后修改时间:" + files[0].lastModified());// 获取文件的字节数,如果是一个文件夹则这个值为0System.out.println("files[0]的大小:" + files[0].length() + " Bytes");// 获取文件路径URI后的路径名System.out.println("files[0]的路径转换为URI:" + files[0].toURI());// 下面的代码逻辑,假设目录下有3个以上文件// 对文件重命名File newfile = new File(file.getParentFile(), "22.txt");  //新的文件名称files[0].renameTo(newfile);// 删除指定的文件、文件夹files[1].delete();// 当虚拟机终止时删除指定的文件、文件夹files[2].deleteOnExit();
}

输出结果如下:

文件目录存在
父节点路径是一个目录
文件存在
路径下有文件:D:\Files\1.txt;D:\Files\2.txt;D:\Files\3.txt;
files[0]1.txt
files[0]的文件路径:D:\Files\1.txt
files[0]的绝对路径:D:\Files\1.txt
files[0]的父文件夹名:D:\Files
files[0]的存在
files[0]的可写
files[0]的可读
file[0]不可执行
files[0]的不是目录
files[0]的是文件
files[0]的路径名是绝对路径
files[0]的最后修改时间:1686814709000
files[0]的大小:8 Bytes
files[0]的路径转换为URI:file:/D:/Files/1.txt

示例代码中,基本比较全面地演示了 File 的一些基本用法,比如文件或者文件夹的新增、重命名、删除,以及获取文件或者文件夹相关信息等操作。

其中有两点地方,值得注意:

  • 第一个就是分隔符的问题。不同的操作系统,路径分隔符是不一样的,这个可以通过File.separator解决,具体实现看下面
  • 第二个就是删除的如果是一个文件夹的话,文件夹下还有文件/文件夹,是无法删除成功的

关于不同操作系统下的路径符号问题解决办法!(windows->“\”;Linux->“/”)

在实际的编程过程中,我们不可能为了区分操作系统,然后又单独写一份文件路径。

可以通过File.separator来实现跨平台的编程逻辑,File.separator会根据不同的操作系统取不同操作系统下的分隔符。

以上面的示范代码为例,我们可以对写法进行如下改造!

// windows 系统下的文件绝对路径定义方式
String path = "d:"+File.separator +"Files"+File.separator+"text.txt";
File file = new File(path);

文件的路径结果会与预期一致!

三、文件的读写操作

对文件的读写,可以通过字节流或者字符流接口来完成,但不管哪种方式,大致分以下几个步骤完成。

  • 第一步:获取一个文件 file 对象
  • 第二步:通过 file 对象,获取一个字节流或者字符流接口的对象,进行读写操作
  • 第三步:关闭文件流

具体的代码实践如下!

3.1、通过字节流接口写入

字节流接口的文件写入,可以通过OutputStream下的子类FileOutputStream来实现文件的数据写入操作。

具体实例如下:

// 创建一个 readWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(!file.exists()){file.createNewFile();
}// 向文件中写入数据(这种方式会覆盖原始数据)
OutputStream outputStream = new FileOutputStream(file);
String str = "我们一起学习Java";
outputStream.write(str.getBytes(StandardCharsets.UTF_8));
outputStream.close();

上面的操作方式会覆盖原始数据,如果想在已有的文件里面,进行追加写入数据,可以如下方式实现。

// 追加数据写入(这种方式不会覆盖原始数据)
OutputStream appendOutputStream = new FileOutputStream(file, true);
String str = "-----这是追加的内容------";
appendOutputStream.write(str.getBytes(StandardCharsets.UTF_8));
appendOutputStream.close();
3.2、通过字节流接口读取

字节流方式的文件读取,可以通过InputStream下的子类FileInputStream来实现文件的数据读取操作。

具体实例如下:

// 获取 readWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(file.exists()){// 获取文件流InputStream input = new FileInputStream(file);// 临时区byte[] buffer = new byte[1024];// 分次读取数据,每次最多读取1024个字节,将数据读取到临时区之中,同时返回读取的字节个数,如果遇到文件末尾,会返回-1int len;while ((len = input.read(buffer)) > -1) {// 字节转为字符串String msg = new String(buffer, 0, len, StandardCharsets.UTF_8);System.out.println(msg);}// 数据读取完毕之后,关闭输入流input.close();
}
3.3、通过字符流接口写入

在之前的文章中,我们了解到为了简化字符的数据传输操作,JDK 提供了 Writer 与 Reader 字符流接口。

字符流方式的文件写入,可以通过Writer下的子类FileWriter来实现文件的数据写入操作。

具体实例如下:

// 创建一个 newReadWriteDemo.txt 文件
File file = new File("newReadWriteDemo.txt");
if(!file.exists()){file.createNewFile();
}
// 实例化Writer类对象
Writer out = new FileWriter(file) ;
// 输出字符串
out.write("Hello");
// 输出换行
out.write("\n");
// 追加信息,append 方法底层本质调用的是 write 方法
out.append("我们一起来学习Java");// 关闭输出流
out.close();
3.4、通过字符流接口读取

字符流方式的文件读取,可以通过Reader下的子类FileReader来实现文件的数据读取操作。

具体实例如下:

// 创建一个 newReadWriteDemo.txt 文件
File file = new File("newReadWriteDemo.txt");
if(file.exists()){// 实例化输入流Reader reader = new FileReader(file);// 临时区char[] buffer = new char[1024];// 分次读取数据,每次最多读取1024个字符,将数据读取到临时区之中,同时返回读取的字节个数,如果遇到文件末尾,会返回-1int len;while ((len = reader.read(buffer)) > -1) {// 字符转为字符串String msg = new String(buffer, 0, len);System.out.println(msg);}// 关闭输入流reader.close();
}
3.5、文件拷贝

在实际的软件开发过程中,避免不了文件拷贝。通过以上的接口方法,我们可以很容易的写出一个文件复制的方法。

比如以字节流操作为例,具体实例如下:

// 1. 创建一个字节数组作为数据读取的临时区
byte[] buffer = new byte[1024];
// 2. 创建一个 FileInputStream 对象用于读取文件
InputStream input = new FileInputStream(new File("input.txt"));
// 3. 创建一个 FileOutputStream 对象用于写入文件
OutputStream output = new FileOutputStream(new File("output.txt"));
// 4. 循环读取文件内容到临时区,并将临时区中的数据写入到输出文件中
int length;
while ((length = input.read(buffer)) != -1) {output.write(buffer, 0, length);
}
// 5. 关闭输入流
input.close();
// 6. 关闭输出流
output.close();

除此之外,JDK 也支持采用缓存流读写技术来实现数据的高效读写

之所为高效,是因为字节缓冲流内部维护了一个缓冲区,读写时先将数据存入缓冲区中,当缓冲区满时再将数据一次性读取出来或者写入进去,这样可以减少与磁盘实际的 I/O 操作次数,可以显著提升读写操作的效率。

比如以字节流缓冲流为例,包装类分别是:BufferedInputStream(字节缓存输入流) 和 BufferedOutputStream(字符缓存输入流)

采用缓冲流拷贝文件,具体实例如下:

// 1. 创建一个字节数组作为数据读取的临时区
byte[] buffer = new byte[1024];
// 2. 创建一个 BufferedInputStream 缓存输入流对象用于读取文件
InputStream bis = new BufferedInputStream(new FileInputStream(new File("input.txt")));
// 3. 创建一个 BufferedOutputStream 缓存输出流对象用于写入文件
OutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("output.txt")));// 4. 循环读取文件内容到临时区,并将缓冲区中的数据写入到输出文件中
int length;
while ((length = bis.read(buffer)) != -1) {bos.write(buffer, 0, length);
}
// 5. 关闭输入流
bis.close();
// 6. 关闭输出流
bos.close();

在大文件的拷贝中,使用缓存流比不使用缓存流技术至少快 10 倍,耗时是很明显的,大家可以亲自试一下。

四、字节流与字符流的互转

在之前的文章中,我们了解到字节流与字符流,两者其实是可以互转的。

其中 InputStreamReader 和 OutputStreamWriter 就是转化桥梁。

4.1、字节流转字符流的操作

字节流转字符流的操作,主要体现在数据的读取阶段,转化过程如下图所示:

以上文中的字节流接口读取文件为例,如果我们想要转换字符流接口来读取数据,具体的操作方式如下:

// 获取 readWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(file.exists()){// 获取字节输入流InputStream inputStream = new FileInputStream(file);// 转字符流输入流,指定 UTF_8 编码规则,读取数据Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);// 缓冲区char[] buffer = new char[1024];// 分次读取数据,每次最多读取1024个字符,将数据读取到缓冲区之中,同时返回读取的字节个数int len;while ((len = reader.read(buffer)) > -1) {// 字符转为字符串String msg = new String(buffer, 0, len);System.out.println(msg);}// 关闭输入流reader.close();inputStream.close();
}

当读取数据的时候,先通过字节流读取,再转成字符流读取。

字节流转字符流,需要指定编码规则,如果没有指定,会取当系统默认的编码规则。

4.2、字符流转字节流的操作

字符流转字节流的操作,主要体现在数据的写入阶段,转化过程如下图所示:

以上文中的字节流接口写入文件为例,如果我们想要转换字符流接口来写入数据,具体的操作方式如下:

// 创建一个 newReadWriteDemo.txt 文件
File file = new File("readWriteDemo.txt");
if(!file.exists()){file.createNewFile();
}// 获取字节输出流
OutputStream outputStream = new FileOutputStream(file);
// 转字符流输出流,指定 UTF_8 编码规则,写入数据
Writer out = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
// 输出字符串
out.write("Hello");
// 输出换行
out.write("\n");
// 追加信息,append 方法底层本质调用的是 write 方法
out.append("我们一起来学习Java");// 关闭输出流
out.close();
outputStream.close();

同样的,当写入数据的时候,先通过字符流写入,再转成字节流输出。

字符流转字节流,也需要指定编码规则,如果没有指定,会取当系统默认的编码规则。

五、小结

本文主要围绕 Java 对磁盘文件的读取和写入数据的方式做了一次简单的总结。

内容难免有所遗漏,欢迎网友留言指出!

六、参考

1、博客园 - 五月的仓颉 - IO和File

七、写到最后

最近无意间获得一份阿里大佬写的技术笔记,内容涵盖 Spring、Spring Boot/Cloud、Dubbo、JVM、集合、多线程、JPA、MyBatis、MySQL 等技术知识。需要的小伙伴可以点击如下链接获取,资源地址:技术资料笔记。

不会有人刷到这里还想白嫖吧?点赞对我真的非常重要!在线求赞。加个关注我会非常感激!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

揿针在医保上叫什么?

点击文末领取揿针的视频教程跟直播讲解 创新型皮内针(揿针)——医保甲类产品 皮内针(揿针)技术属于重点推广的中医适宜技术,是将特制的小型针具固定于腧穴部位的皮内或皮下做较长时间留针的一种方法,称“…

2024年 C++音视频开发学习路线(ffmpeg/rtsp/srs/webrtc/hls)

在音视频工作领域,很多人可能会陷入徘徊和迷茫的境地。音视频的知识纷繁复杂,自己学习非常困难,既需要非常扎实的基础知识,又需要有很多的工程经验;不知道如何学,怎样才能查漏补缺自己的技术短板。 对于音…

QT C++ widget layout 嵌套 例子2

在上篇文章中描述了实中套虚(用setLayout),虚中套实(用addWidget)。 本文再加1条,虚中套虚(用addLayout)。 所谓虚中套虚,是layout 套 layout 。 另外用循环代码生成从…

记录接口请求偶发504 Gateway Time-out问题

项目场景: 我们将服务部署到A公司服务器中,使用了共五台服务器,分别是:1.NG服务器 2.日志服务器 3.缓存服务器 4.应用服务器1 5.应用服务器2 。而请求过来首先到达的是他们的物理代理服务器,然后再转发请求到我们的ng…

【Neo4jJDK开箱即用的安装全流程】

neo4j:命令行本地访问loclhost neo4j:命令行本地访问loclhost2 neo4j操作 Neo4j桌面版数据库导出导入 Neo4j安装与配置以及JDK安装与配置教程(超详细) Neo4j 安装、使用教程 Neo4j安装教程 Neo4J桌面版的配置和连接Pycharm jdk-neo对应版本 JDK ORACLE中…

数据结构(四)————二叉树和堆(中)

制作不易,三连支持一下呗!!! 文章目录 前言一、堆的概念及结构二、堆的实现三.堆的应用 总结 前言 CSDN 这篇博客介绍了二叉树中的基本概念和存储结构,接下来我们将运用这些结构来实现二叉树 一、堆的概念及结构 1…

用sunoAI写粤语歌的方法,博主已经亲自实践可行

粤语歌还是很好听的,那么如何使用suno进行粤语歌的创作呢? 本文和大家进行分享下如何进行粤语歌曲的创作。 访问地址如下(电脑端/手机端一个地址): ​https://suno3.cn/#/?i8NCBS8_WXTT 在微信浏览器中也可以直接…

css 案例 横向滚动渐变

效果 完整代码&#xff1a; <template><view class"content"><view class"tab"><view class"tab-item" v-for"(item,index) in tab" :key"index" click"handlerTab(index)":class"ind…

winserver系统设置图片查看器

新建 .bat 批处理执行文件&#xff0c;内容如下&#xff1a; echo off&cd&color 0a&cls echo Set Win10 Photo Viewer reg add "HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations" /v ".jpg" /t REG_SZ /d Photo…

MySQL——利用变量进行查询操作

新建链接&#xff0c;自带world数据库&#xff0c;里面自带city表格。 DQL # MySQL利用变量进行查询操作 set cityNameHaarlemmermeer; select * from city where NamecityName;# 多个结果查询 set cityName1Haarlemmermeer; set cityName2Breda; set cityName3Willemstad; s…

古月居讲师/签约作者招募计划

机器人&#xff0c;作为一个集成了多学科技术的复杂系统&#xff0c;其开发过程充满了挑战。为了帮助开发者们更好地克服这些挑战&#xff0c;提升项目的开发效率和质量&#xff0c;古月居特别招募[博客签约作者/课程讲师]。如果您平常热爱记录、分享开发者经验的习惯&#xff…

Emby for Mac(轻松管理多媒体影音库)1.9.9中文版

Emby for Mac是一款强大的多媒体影音库管理工具&#xff0c;可以帮助用户轻松管理和浏览自己的影音资源。它可以将用户的个人视频、音乐和照片组合在一起&#xff0c;并将其流式传输到用户的设备上。 Emby for Mac 1.9.9中文版下载 Emby for Mac具有易于使用的界面&#xff0c;…

机器学习案例:加州房产价格(四)

参考链接&#xff1a;https://hands1ml.apachecn.org/2/#_12 数据探索和可视化、发现规律 通过之前的工作&#xff0c;你只是快速查看了数据&#xff0c;对要处理的数据有了整体了解&#xff0c;现在的目标是更深的探索数据。 首先&#xff0c;保证你将测试集放在了一旁&…

【Docker系列】Linux部署Docker Compose

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

山东济南中国当代文化名人颜廷利:大自然赋予人类众生的真正贵重礼物

大自然赋予了众生---火&#xff08;太阳&#xff0c;万物生长靠太阳&#xff09;、水&#xff08;河流&#xff0c;水是生命之源&#xff09;、木&#xff08;空气&#xff0c;生命就在一翕一合的呼吸之间&#xff09;、土&#xff08;大地&#xff0c;坤为大地之母&#xff0c…

Hive-拉链表的设计与实现

Hive-拉链表的设计与实现 在Hive中&#xff0c;拉链表专门用于解决在数据仓库中数据发生变化如何实现数据存储的问题。 1.数据同步问题 Hive在实际工作中主要用于构建离线数据仓库&#xff0c;定期的从各种数据源中同步采集数据到Hive中&#xff0c;经过分层转换提供数据应用…

【JAVA SE】初识JAVA

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;JAVA 个人主页&#xff1a;Celias blog~ 目录 ​编辑 一、关于JAVA 1.1 JAVA语言简介 1.2 语言优势 1…

链表常见OJ题

目录 题目一&#xff1a;移除链表元素 &#xff08;1&#xff09;题目链接 &#xff08;2&#xff09;题目要求 &#xff08;3&#xff09;题解 题目二&#xff1a;反转链表 &#xff08;1&#xff09;题目链接 &#xff08;2&#xff09;题目要求​编辑 &#xff08;3…

项目9-网页聊天室1(注册+Bycrpt加密)

1.准备工作 1.1.前端页面展示 1.2 数据库的建立 我们通过注册页面&#xff0c;考虑如何设计用户表数据库。 用户id&#xff0c;userId用户名&#xff0c;唯一&#xff0c;username用户密码&#xff0c;password&#xff08;包括密码和确认密码ensurePssword【数据库没有该字段…

【简单介绍下Milvus】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…