当前位置: 首页 > news >正文

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 &#xff0c;在字节码文件中对应多个指令&#xff0c;多个线程在运行多个指令时&#xff0c;就存在原子性、可见性问题 赋值 多线程场景下&#xff0c;一个指令如果包含多个字节码指令&#xff0c;那么就不再是原子操作。因为赋值的同时&#xff0c…...

错误:EfficientDet网络出现“No boxes to NMS“并且mAP:0.0的解决方案

近日&#xff0c;在使用谷歌新推出来的一个网络EfficientDet进行目标检测训练自己的数据集的时候&#xff0c;出现了如下错误&#xff1a; 其中项目开源地址是&#xff1a;https://github.com/toandaominh1997/EfficientDet.Pytorch 上面截图中的1和2代表我的类别名称。读者可…...

python的opencv操作记录13——区域生长及分水岭算法

文章目录图像区域基本算法——形态学运算腐蚀与膨胀开运算与闭运算opencv中的形态学运算距离计算——distanceTransform函数连通域连通的定义计算连通域——connectedComponents连通域实验基于区域的分割区域生长算法自定义一个最简单区域生长算法实现区域分割一般区域分割open…...

一文看懂网上下单的手机流量卡为什么归属都是随机的!

最近很多网上下单的小伙伴们心中似乎都有一个疑问。那就是网上很多手机卡、流量卡都不能自选号码和归属地&#xff0c;就算能自选号码&#xff0c;归属地也是随机的而且很多都不会跟你说具体的城市&#xff0c;这是为什么呢&#xff1f;莫非其中有什么不可告人的秘密吗?小伙伴…...

python Pytest生成alluer测试报告的完整教程

1.下载allure包到本地&#xff0c;解压 网上很多资料&#xff0c;这边不提供了 2.配置环境变量 将上面解压后bin文件的路径复制&#xff0c;添加到环境变量Path下 3.验证环境变量配置是否功 在cmd中输入allure&#xff0c;回车 。查看allure是否成功&#xff1a; 4.pyc…...

4-spring篇

ApplicationContext refresh的流程 12个步骤 prepareRefresh 这一步创建和准备了Environment对象&#xff0c;并赋值给了ApplicationContext的成员变量 要理解Environment对象的作用 obtainFreshBeanFactory ApplicationContext 里面有一个成员变量&#xff0c;Beanfactory b…...

提升 Web 应用程序的性能:如何使用 JavaScript 编写缓存服务

缓存是一种重要的优化技术&#xff0c;用于加速数据访问和降低服务器负载。缓存存储经常访问的数据&#xff0c;以便在需要时可以快速检索。在本文中&#xff0c;我们将探索如何使用简单的数据结构在 JavaScript 中编写缓存服务。 编码缓存服务的第一步是定义将用于访问缓存的…...

供应商绩效管理指南:挑战、考核指标与管理工具

管理和优化供应商绩效既关键又具有挑战性。要知道价格并不是一切&#xff0c;如果你的供应商在商定的价格范围内向你开具发票&#xff0c;但服务达不到标准或货物不合格&#xff0c;你也无法达到节约成本的目标。 供应商绩效管理可以深入了解供应商可能带来的风险&#xff0c…...

干货文稿|详解深度半监督学习

分享嘉宾 | 范越文稿整理 | William嘉宾介绍Introduction to Semi-Supervised Learning传统机器学习中的主流学习方法分为监督学习&#xff0c;无监督学习和半监督学习。这里存在一个是问题是为什么需要做半监督学习&#xff1f;首先是希望减少标注成本&#xff0c;因为目前可以…...

信箱|邮箱系统

技术&#xff1a;Java、JSP等摘要&#xff1a;在经济全球化和信息技术飞速发展的今天&#xff0c;通过邮件收发进行信息传递已经成为主流。目前&#xff0c;基于B/S&#xff08;Browser/Server&#xff09;模式的MIS&#xff08;Management information system&#xff09;日益…...

JS数组拓展

1、Array.from Array.from 方法用于将两类对象转为真正的数组&#xff1a; 类似数组的对象,所谓类似数组的对象&#xff0c;本质特征只有一点&#xff0c;即必须有length属性。 因此&#xff0c;任何有length属性的对象&#xff0c;都可以通过Array.from方法转为数组 和 可遍历…...

一道很考验数据结构与算法的功底的笔试题:用JAVA设计一个缓存结构

我在上周的笔试中遇到了这样一道题目&#xff0c;觉得有难度而且很考验数据结构与算法的功底&#xff0c;因此Mark一下。 需求说明 设计并实现一个缓存数据结构: 该数据结构具有以下功能&#xff1a; get(key) 如果指定的key存在于缓存中&#xff0c;则返回与该键关联的值&am…...

(10)C#传智:命名空间、String/StringBuilder、指针、继承New(第10天)

内容开始多了&#xff0c;慢品慢尝才有滋味。 一、命名空间namespace 用于解决类重名问题&#xff0c;可以看作类的文件夹. 若代码与被使用的类&#xff0c;与当前的namespace相同&#xff0c;则不需要using. 若namespace不同时&#xff0c;调用的方法&#xff1a…...

基于Jetson Tx2 Nx的Qt、树莓派等ARM64架构的Ptorch及torchvision的安装

前提 已经安装好了python、pip及最基本的依赖库 若未安装好点击python及pip安装请参考这篇博文 https://blog.csdn.net/m0_51683386/article/details/129320492?spm1001.2014.3001.5502 特别提醒 一定要先根据自己板子情况&#xff0c;找好python、torch、torchvision的安…...

MySQL存储引擎详解及对比和选择

什么是存储引擎&#xff1f; MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术&#xff0c;你能够获得额外的速度或者功能&#xff0c;从而改善…...

【推拉框-手风琴】vue3实现手风琴效果的组件

简言 在工作时有时会用到竖形手风琴效果的组件。 在此记录下实现代码和实现思路。 手风琴实现 结构搭建 搭建结构主要实现盒子间的排列效果。 用flex布局或者其他布局方式将内容在一行排列把每一项的内容和项头用盒子包裹&#xff0c; 内容就是这一项要展示的内容&#xf…...

滑动窗口最大值:单调队列

239. 滑动窗口最大值 难度困难2154收藏分享切换为英文接收动态反馈 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例…...

负载均衡算法

静态负载均衡 轮询 将请求按顺序轮流地分配到每个节点上&#xff0c;不关心每个节点实际的连接数和当前的系统负载。 优点&#xff1a;简单高效&#xff0c;易于水平扩展&#xff0c;每个节点满足字面意义上的均衡&#xff1b; 缺点&#xff1a;没有考虑机器的性能问题&…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...