IO详解(文件,流对象,一些练习)
目录
文件
文件概念
文件的路径
路径有俩种表示风格
文件类型
如何区分文本文件还是二进制文件?
java对文件的操作
File类中的一些方法
流对象
流对象的简单概念
java标准库的流对象
1.字节流,(操作二进制数据的)
2.字符流 (操作文本数据的)
流对象最核心的四个操作
注意,intput 和 output的方向
读文件(字节流)
read无参数版本
read一个参数版本
理解read的行为和返回值
写文件
关于close
如何确保close被执行到
字符流
读操作
写操作
关于Scanner
练习
用户输入一个查询的词,看看当前目录下(以及子目录里)是否有匹配的结果,如果有匹配结果,就询问用户是否删除
把一个文件拷贝成另一个文件(把第一个文件按照字节读取,把结果写入到另一个文件中)
文件
文件概念
狭义的文件:指的是硬盘上的 文件 和 目录(文件夹)
广义的文件:泛指计算机中的很多 软硬件资源
操作系统中,把很多的硬件设备和软件资源抽象成了文件,按照文件的方式来统一管理.
例如:在网络编程中的网卡,操作系统是把网卡当作一个文件来进行操作的
文件的路径
之前学习的代码中,存储数据,主要靠变量,变量是在内存中的
现在学习的文件,则是在硬盘上
每个文件,在硬盘上都有一个具体的路径

路径有俩种表示风格
1.绝对路径:以c:d:盘符开头的路径
2.相对路径:以当前所在目录为基准,以.或..开头(.有时可以省略),找到指定路径
当前所在目录:称为工作目录,每个程序运行的时候,都有一个工作目录(在控制台里通过命令操作较为明显)

假定,当前的工作目录是,d:/tmp
tmp目录下有111这个目录,定位到111这个目录,就可以表示成
./111(./就表示的是当前的目录 d:/tmp)
../表示当前目录的上级目录,如果工作目录是d:/tmp/222 想要定位到111这个目录,相对路径写作.
../111(..表示当前目录d:/tmp/222 的上级目录 d:/tmp)
文件类型

如何区分文本文件还是二进制文件?
直接使用 记事本 打开,如果乱码了,说明是二进制文件,如果没乱,就是文本文件
java对文件的操作
1.针对文件系统操作(文件的创建,删除,重命名)
2.针对文件内容操作(文件读和写)
java标准库提供了File这个类

在new File 对象的时候,构造方法参数中,可以指定一个路径.此时File对象代表这个路径对应的文件
File类中的一些方法
方法
代码
public static void main(String[] args) throws IOException {File file = new File("./test.txt");System.out.println(file.getName());System.out.println(file.getParent());System.out.println(file.getAbsoluteFile());System.out.println(file.getPath());System.out.println(file.getCanonicalFile());}
运行结果

方法

代码
public static void main(String[] args) throws IOException {File file = new File("D:/test.txt");file.createNewFile();System.out.println(file.exists());System.out.println(file.isFile());System.out.println(file.isDirectory());}
运行结果

方法

代码
public static void main(String[] args) throws IOException {File file = new File("D:/test.txt");System.out.println(file.exists());file.createNewFile();System.out.println(file.exists());file.delete();System.out.println(file.exists());}
运行结果

方法

代码
public static void main(String[] args) {File file = new File("./test");file.mkdir();}
public static void main(String[] args) {File file = new File("./test/aaa/bbb");file.mkdirs();}
运行结果

流对象
流对象的简单概念
针对文件内容,使用"流对象" 进行操作,从文件中读100个字节,我们可以一次读100个字节,一次读完
也可以一次读20个字节,5次读完,我们可以随心所欲的读
java标准库的流对象
从类型上分为俩大类
1.字节流,(操作二进制数据的)
InputStream FileInputStream
OutputStream FileOutputStream
2.字符流 (操作文本数据的)
Reader FileReader
Writer FileWriter
流对象最核心的四个操作
这些类的使用方式是固定的,核心就是四个操作
1.打开文件(构造对象)
2.读写文件(read) ==>针对的是 InputStream/Reader
3.写文件(writer) ==> 针对OutputStream/Writer
4.关闭文件(close)
注意,intput 和 output的方向
我们是以CPU为中心,来看待这个方向的
数据朝着CPU的方向流向,就是输入,所以把从硬盘中读取数据到内存 这个过程称为读 input
数据远离CPU的方向流向,就是输入,所以把从内存中写数据到硬盘 这个过程称为写 output
读文件(字节流)
read无参数版本
代码
public static void main(String[] args) throws IOException {
//创建 InputStream 对象的时候,使用绝对路径或者相对路径,都可以,也可以使用File对象InputStream inputStream = new FileInputStream("D:/test.txt");
//进行读操作while (true){int b = inputStream.read();if(b == -1){break;}System.out.println(""+(byte)b);}inputStream.close();
}

运行结果
D盘中test的文件内容

read一个参数版本
public static void main(String[] args) throws IOException {//创建 InputStream 对象的时候,使用绝对路径或者相对路径,都可以,也可以使用File对象InputStream inputStream = new FileInputStream("D:/test.txt");while(true){byte[] buffer = new byte[1024];int len = inputStream.read(buffer);System.out.println("len "+len);if(len == -1){break;}for (int i = 0; i < len; i++) {System.out.println(""+buffer[i]);}}inputStream.close();}
运行结果


理解read的行为和返回值
上面这里给的数组长度是1024,read就会尽可能读取1024个字节,填到数组里.但实际上,文件剩余长度是有限的,如果剩余长度超过1024,此时1024个字节就会填满,返回值是1024,如果当前剩余的长度不足1024,此时有多少就填多少,read方法就会返回当前实际读取的长度
第二个版本的代码有什么好处?
buffer存在的意义,是为了提高IO效率,单次IO操作,是要访问硬盘IO设备,单次操作是比较消耗时间的
如果频繁进行这样的IO操作,耗时比较大
单次IO时间是一定的,如果能缩短IO次数,此时就可以提高程序的整体效率了
第一个版本的代码,是一次读取一个字节,循环次数比较高,read次数很高,读取IO次数也很高
第二个版本的代码,是一次读取1024个字节,循环次数降低了很多,read次数变少了
写文件
代码
public static void main(String[] args) throws IOException {OutputStream outputStream = new FileOutputStream("D:/test.txt")outputStream.write(97);outputStream.write(98);outputStream.write(99);outputStream.write(100);outputStream.close();}
运行结果

对于OutputStream 来说,默认情况下,打开一个文件,会先清空文件原有的内容(这样,之前的"hello"就被清空了)
如果不想清空,流对象还提供了一个"追加写"对象,通过这个就可以实现不清空文件,把新内容追加到后面.
关于close
对于上述代码中的outputStream.close();这里的close操作,含义是关闭文件
一个线程对于一个PCB,一个进程对应1个或多个PCB
PCB有一个重要的属性,文件描述符表(相当于一个数组),记录了该进程打开了哪些文件.(即使一个进程有多个线程多个PCB也没关系,这些PCB共用一个文件描述符表)

如果没有close,对应的表项,没有及时释放.虽然 java有GC,GC操作会在回收这个outputStream对象的时候完成释放操作,但是这个GC不一定及时...
所以,如果不能手动释放,意味着文件描述符表可能很快就被占满了(文件描述符表这个数组,不能自动扩容,有上限)
如果占满了后,再次打开文件,就会打开失败
close 一般来说是要执行的,但是如果一个程序,有一些文件对象自始至终都要使用,也可以不用关闭
随着进程结束,PCB销毁了,文件描述符表也就销毁了,对应的资源操作系统就自动回收了,因此,如果一个文件close之后,程序就立即结束了,此时也可以省略close
有时我们可能会发现,写文件的内容没有真正在文件中出现,很大可能是因为缓存区,
写操作其实是,先写到缓冲区里(缓冲区有很多种形态,自己写的代码里可以有缓冲区,标准库里也可以有缓冲区,操作系统内核里也可以有缓冲区)
写操作执行完了,内容可能在缓冲区,还没有真正进入硬盘,close操作 就会触发缓冲区的刷新(刷新操作就是把缓冲区的内容写到硬盘里)
除了close之外,还可以通过flush方法刷新缓冲区(此时文件不会立即关闭)
如何确保close被执行到
刚刚的代码可以改成这样
public static void main(String[] args) throws IOException {try(OutputStream outputStream = new FileOutputStream("D:/test.txt")) {outputStream.write(97);outputStream.write(98);outputStream.write(99);outputStream.write(100);}}
这是更推荐的写法,这个写法虽然没有显示的写 close,实际上会执行的,只要try语句块执行完毕,就可以自动执行到close
这个语法,在java中被称为try with resources ,当然不是随便拿一个对象放在try()里就能自动释放,必须要这个对象实现了Closeable接口

实现了这个Closeable接口的类才可以放到try()中被自动关闭,这个接口提供的方法就是close方法
字符流
读操作
代码
public static void main(String[] args) throws IOException {try(Reader reader = new FileReader("D:/test.txt")){while(true){int ch = reader.read();if(ch == -1){break;}System.out.println((char)ch+"");}}}
运行结果

写操作
public static void main(String[] args) throws IOException {try(Writer writer = new FileWriter("D:/test.txt")){writer.write("hello world");}}
运行结果

关于Scanner
Scanner是搭配流对象来使用的
代码
public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("D:test.txt")) {//此时读取的内容就是从 文件 中读取了Scanner scanner = new Scanner(inputStream);scanner.next();}}

练习
用户输入一个查询的词,看看当前目录下(以及子目录里)是否有匹配的结果,如果有匹配结果,就询问用户是否删除
代码
import java.io.File;
import java.util.Scanner;public class IODemo10 {static Scanner scanner = new Scanner(System.in);public static void main(String[] args) {//让用户搜索一个指定搜索的目录System.out.println("请输入要搜索的路径: ");String basePath = scanner.next();//针对用户输入进行简单判定File root = new File(basePath);if(!root.isDirectory()){//路径不存在,或者只是一个普通的文件,此时无法进行搜索System.out.println("输入的目录有误!");return;}//再让用户输入一个要删除的文件名System.out.println("请输入要删除的文件");//此处要使用next,而不能使用nextLineString nameToDelete = scanner.next();//针对指定的路径进行扫描,递归操作//先从根目录出发//判定一下,当前的这个目录里,是否包含我们所需要删除的目录.如果是则删除,否则跳过下一个//如果当前目录里包含一些目录,再针对子目录进行递归scanDir(root,nameToDelete);}private static void scanDir(File root, String nameToDelete) {//1.先列出 root 下的文件和目录File[] files = root.listFiles();if(files == null){//当前root 目录下没有东西,是一个空目录//结束继续递归return;}//2.遍历当前列出的结果for(File x : files){if(x.isDirectory()){//如果是目录,就进一步递归scanDir(x,nameToDelete);}else{//如果是普通文件,则判定是否要删除if(x.getName().contains(nameToDelete)){System.out.println("确实是否要删除: "+x.getAbsolutePath()+"嘛");String choice = scanner.next();if(choice.equals("y")||choice.equals("Y")){x.delete();System.out.println("删除成功");}else{System.out.println("删除取消");}}}}}
}
运行结果

把一个文件拷贝成另一个文件(把第一个文件按照字节读取,把结果写入到另一个文件中)
代码
import java.io.*;
import java.util.Scanner;public class IODemo11 {public static void main(String[] args) throws IOException {//输入俩个路径//源 和 目标(从哪里,拷贝到哪里)Scanner scanner = new Scanner(System.in);System.out.println("请输入要拷贝哪个文件: ");String srcPath = scanner.next();System.out.println("请输入要拷贝到哪个地方: ");String destPath = scanner.next();File srcFile = new File(srcPath);if(!srcFile.isFile()){//如果源路径不是一个文件(是一个目录,或者不存在)//此时不做任何操作System.out.println("输入的源路径有误");return;}File destFile = new File(destPath);if(destFile.isFile()){//如果目标路径已经存在,认为不能拷贝System.out.println("当前输入的目标路径有误");return;}//进行拷贝操作try(InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(destFile)){//进行读文件操作while(true){int b = inputStream.read();if(b == -1){break;}//进行写操作outputStream.write(b);}}}
}
相关文章:
IO详解(文件,流对象,一些练习)
目录 文件 文件概念 文件的路径 路径有俩种表示风格 文件类型 如何区分文本文件还是二进制文件? java对文件的操作 File类中的一些方法 流对象 流对象的简单概念 java标准库的流对象 1.字节流,(操作二进制数据的) 2.字符流 (操作文本数据的) 流对象最核心的四个…...
SpringCloud全家桶— — 【1】eureka、ribbon、nacos、feign、gateway
SpringCloud全家桶— — 组件搭建 1 Eureka 1.1 Eureka-server 创建eureka-server的SpringBoot项目 ①导入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId…...
【线程安全篇】
线程安全之原子性问题 x ,在字节码文件中对应多个指令,多个线程在运行多个指令时,就存在原子性、可见性问题 赋值 多线程场景下,一个指令如果包含多个字节码指令,那么就不再是原子操作。因为赋值的同时,…...
错误:EfficientDet网络出现“No boxes to NMS“并且mAP:0.0的解决方案
近日,在使用谷歌新推出来的一个网络EfficientDet进行目标检测训练自己的数据集的时候,出现了如下错误: 其中项目开源地址是:https://github.com/toandaominh1997/EfficientDet.Pytorch 上面截图中的1和2代表我的类别名称。读者可…...
python的opencv操作记录13——区域生长及分水岭算法
文章目录图像区域基本算法——形态学运算腐蚀与膨胀开运算与闭运算opencv中的形态学运算距离计算——distanceTransform函数连通域连通的定义计算连通域——connectedComponents连通域实验基于区域的分割区域生长算法自定义一个最简单区域生长算法实现区域分割一般区域分割open…...
一文看懂网上下单的手机流量卡为什么归属都是随机的!
最近很多网上下单的小伙伴们心中似乎都有一个疑问。那就是网上很多手机卡、流量卡都不能自选号码和归属地,就算能自选号码,归属地也是随机的而且很多都不会跟你说具体的城市,这是为什么呢?莫非其中有什么不可告人的秘密吗?小伙伴…...
python Pytest生成alluer测试报告的完整教程
1.下载allure包到本地,解压 网上很多资料,这边不提供了 2.配置环境变量 将上面解压后bin文件的路径复制,添加到环境变量Path下 3.验证环境变量配置是否功 在cmd中输入allure,回车 。查看allure是否成功: 4.pyc…...
4-spring篇
ApplicationContext refresh的流程 12个步骤 prepareRefresh 这一步创建和准备了Environment对象,并赋值给了ApplicationContext的成员变量 要理解Environment对象的作用 obtainFreshBeanFactory ApplicationContext 里面有一个成员变量,Beanfactory b…...
提升 Web 应用程序的性能:如何使用 JavaScript 编写缓存服务
缓存是一种重要的优化技术,用于加速数据访问和降低服务器负载。缓存存储经常访问的数据,以便在需要时可以快速检索。在本文中,我们将探索如何使用简单的数据结构在 JavaScript 中编写缓存服务。 编码缓存服务的第一步是定义将用于访问缓存的…...
供应商绩效管理指南:挑战、考核指标与管理工具
管理和优化供应商绩效既关键又具有挑战性。要知道价格并不是一切,如果你的供应商在商定的价格范围内向你开具发票,但服务达不到标准或货物不合格,你也无法达到节约成本的目标。 供应商绩效管理可以深入了解供应商可能带来的风险,…...
干货文稿|详解深度半监督学习
分享嘉宾 | 范越文稿整理 | William嘉宾介绍Introduction to Semi-Supervised Learning传统机器学习中的主流学习方法分为监督学习,无监督学习和半监督学习。这里存在一个是问题是为什么需要做半监督学习?首先是希望减少标注成本,因为目前可以…...
信箱|邮箱系统
技术:Java、JSP等摘要:在经济全球化和信息技术飞速发展的今天,通过邮件收发进行信息传递已经成为主流。目前,基于B/S(Browser/Server)模式的MIS(Management information system)日益…...
JS数组拓展
1、Array.from Array.from 方法用于将两类对象转为真正的数组: 类似数组的对象,所谓类似数组的对象,本质特征只有一点,即必须有length属性。 因此,任何有length属性的对象,都可以通过Array.from方法转为数组 和 可遍历…...
一道很考验数据结构与算法的功底的笔试题:用JAVA设计一个缓存结构
我在上周的笔试中遇到了这样一道题目,觉得有难度而且很考验数据结构与算法的功底,因此Mark一下。 需求说明 设计并实现一个缓存数据结构: 该数据结构具有以下功能: get(key) 如果指定的key存在于缓存中,则返回与该键关联的值&am…...
(10)C#传智:命名空间、String/StringBuilder、指针、继承New(第10天)
内容开始多了,慢品慢尝才有滋味。 一、命名空间namespace 用于解决类重名问题,可以看作类的文件夹. 若代码与被使用的类,与当前的namespace相同,则不需要using. 若namespace不同时,调用的方法:…...
基于Jetson Tx2 Nx的Qt、树莓派等ARM64架构的Ptorch及torchvision的安装
前提 已经安装好了python、pip及最基本的依赖库 若未安装好点击python及pip安装请参考这篇博文 https://blog.csdn.net/m0_51683386/article/details/129320492?spm1001.2014.3001.5502 特别提醒 一定要先根据自己板子情况,找好python、torch、torchvision的安…...
MySQL存储引擎详解及对比和选择
什么是存储引擎? MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善…...
【推拉框-手风琴】vue3实现手风琴效果的组件
简言 在工作时有时会用到竖形手风琴效果的组件。 在此记录下实现代码和实现思路。 手风琴实现 结构搭建 搭建结构主要实现盒子间的排列效果。 用flex布局或者其他布局方式将内容在一行排列把每一项的内容和项头用盒子包裹, 内容就是这一项要展示的内容…...
滑动窗口最大值:单调队列
239. 滑动窗口最大值 难度困难2154收藏分享切换为英文接收动态反馈 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例…...
负载均衡算法
静态负载均衡 轮询 将请求按顺序轮流地分配到每个节点上,不关心每个节点实际的连接数和当前的系统负载。 优点:简单高效,易于水平扩展,每个节点满足字面意义上的均衡; 缺点:没有考虑机器的性能问题&…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
