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

【JavaEE】文件IO操作

目录

  • 什么是文件
  • 文件的组织形式
  • 文件路径
    • 相对路径和绝对路径
  • 文件的种类
  • Java中的文件操作
    • File类的属性
      • File类的构造方法
      • File类的常用方法
  • JavaIO操作
    • 文件缓冲区
    • 文件流
    • 字节流
      • 读(InputStream)
      • 写(OutputStream)
    • 字符流
      • 读(Reader)
      • 写(write)
  • 小练习
    • case1
    • case2
    • case3

什么是文件

  • 狭义上的文件指的就是存储在硬盘空间里面的文件.
  • 广义上的文件指的就是操作系统管理资源的一种机制, 很多软硬件资源把他抽象成文件来表示.
  • 文件夹在计算机专业术语上指的是目录
  • 为什么要用文件? 我们程序输入的数据一般随着进程结束, 那么这个数据是临时保存在内存里面的就会被清空. 如果我们下次运行程序还要执行这个数据, 那么就需要我们再次手动输入. 而如果我们不想手动输入, 就可以用第三方介质硬盘完成可持久化存储, 那么我们下次要用这部分的数据, 就直接可以从硬盘里面读取. 可是如果说我们要存储, 那么怎么管理这些数据. 就是用文件来管理组织这些数据.

文件的组织形式

  • 随着文件越来越多, 我们就需要一个数据结构来管理这些文件. 而我们就采用了树形结构来管理这些文件. 这里就引入了目录(文件夹)的概念, 一个目录里面可以有多个文件或目录, 目录里面的文件或目录就可以看成子节点, 而他们的父节点就是包含他们的目录.
  • 这里目录包含的文件或目录数量是不一定的, 即他的子节点数量不一定. 那么整个树形结构是一颗N叉树
  • 文件除了有数据内容之外,还有文件本身的一个信息,例如:文件名、文件类型、文件大小,文件路径、文件源地址,我们把这一块这信息称之文件的 “元信息”。
    在这里插入图片描述

文件路径

  • 现在硬盘上的文件越来越多. 那么如果说我们要查找一个文件的位置应该如何查找呢? 他的位置又该如何表示呢? 这就引入了文件路径这个概念
  • 从树根开始(电脑上通常从那个盘(C盘, D盘))开始查找对应的文件, 这个过程中所涉及到的包含查找文件的目录. 把这些目录记录下来, 就形成了文件路径. 一般使用"/"来分割路径中的多级目录
    在这里插入图片描述

相对路径和绝对路径

  • 盘符(C盘或D盘这些)为根节点开始,逐渐向子节点延申,直到找到目标文件,那么找到该文件的所经过的节点,就称之为文件路径,从根节点开始扫描这种描述方式也被称之为文件的 “绝对路径”。
  • 举个例子:D:\JAVA\JDK\bin\jave.exe 这是一个绝对路径
    在这里插入图片描述
  • 而相对路径呢则不一定是从盘符开始, 他是看谁是他的基准路径.也就是上一级路径是谁?比如C:\user\root, 基准路径是C:\user. 如果说我们要查找root这个文件, 那么我们是基于C:\user这个路径下查找. 这就是基准路径
  • " . " 符号在相对路径中是一个特殊符号,表示当前目录
  • " … " 符号也是特殊符号,表示当前目录中的上级目录
  • 在相对路径的情况下要描述当前目录的上上级目录,或者级别更高的目录时,可以使用 “…\ …\ …\ ” 的形式(windowns操作系统允许使用\当分割符, 也可以使用/当分隔符),每一个 " …/ " 表示上一个目录。

文件的种类

  • 从开发的角度来分类, 文件分为二进制文件和文本文件.
  • 二进制文件是冯诺依曼祖师爷规定的, 所有的文件的是二进制的. 所以叫做二进制文件. 比如我们的 图片, 音视频文件都是二进制的.
  • 文本文件其实实质上也是二进制文件, 但是由于编码表的原因, 文本文件的二进制刚好能够对应上编码表上的文本(如ascill, utf8), 这些映射出来的文本能够组成有意义的文本. 就叫做文本文件

Java中的文件操作

File类的属性

  • 这里的分隔符指的就是我们文件路径中的分割符/或(反斜杠), 其中"" Windows系统支持, 其他大部分系统只支持"/"

在这里插入图片描述

File类的构造方法

在这里插入图片描述

File类的常用方法

在这里插入图片描述

JavaIO操作

文件缓冲区

  • 文件缓冲区的作用就是解决因为硬盘IO速度太慢导致内存等待时间太久, 这个时候为了解决速度匹配问题, 我们不让内存直接和硬盘进行交互. 而是让内存和文件缓冲区交互, 而文件缓冲区担任缓存硬盘数据的任务, 那么当缓冲区存满了数据. 一次性交给内存处理. 减少硬盘和内存IO次数
  • 这就好比我们嗑瓜子一样, 我们如果离垃圾桶很远, 那么我们每嗑一个瓜子如果都要跑到垃圾桶哪里去扔, 那么太耗费时间了. 不让用一张纸缓存瓜子壳, 一次性把大量的瓜子交给垃圾桶.
    在这里插入图片描述

文件流

  • 为什么叫文件流? 流我们就会想到一个词叫流水, 那么接(读取)这个水, 可以有很多种方法, 每次度100ml, 每次读50ml都可以. 那么对于数据也是一样. 这里的数据就是我们的流水. 每次可以读100字节, 每次也可以读50字节. 对于灌(写入)也是一样, 我们可以每次灌100ml, 也可以灌50ml. 那么我们写入数据也是一样, 每次可以写入100字节, 每次也可以写入50字节

在这里插入图片描述

字节流

  • 字节流就是我们读写数据是以字节为单位进行读写.

读(InputStream)

  • InputStream类的常用方法
    在这里插入图片描述
  • 注意的是InputStream类是一个抽象类. 我们并不能直接使用他来创建对象从而使用对象方法. 而是要用他的子类FileInputStream 类。
  • FileInputStream类的构造方法
    在这里插入图片描述
public class demo1 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")){//读文件操作while(true){byte[] data = new byte[1024];//这里进行读文件操作//read方法会尽量把data数组填满, 填不满的话, 能填几个是几个//此处的n就表示读取了几个字节int n = inputStream.read(data);if(n == -1){break; //文件读取完}for(int i = 0; i < n; i++){System.out.printf("0x%x\n", data[i]);}}}}
}
  • 这里我们读取test文件里面是你好的内容, 以字节方式读取, 存储在data数组中. 然后按16进制打印字节. 可以对照utf8编码表, 这样的字节码对应你好
    在这里插入图片描述
  • 这里解释一下 try(InputStream inputStream = new FileInputStream(“./test.txt”)), 这是try with resource写法, 这么写是为了我们打开文件后自动关闭文件也就是调用close方法. 如果文件资源不关闭那么就会导致文件资源泄露的问题(占着厕所不拉shit)
  • List item

Java中提供了"try-with-resources"语句,用于自动关闭实现了"AutoCloseable"接口(没实现这个接口就不能自动关闭, 比如ReentrantLock就是没有实现)的资源,无需显式调用close()方法来关闭资源。这个语句可以在代码块结束后自动关闭资源,无论代码块是正常执行完毕还是发生了异常。

写(OutputStream)

  • 他的常用方法

在这里插入图片描述

  • 对于OutputStream来说, 默认会尝试创建不存在的问题. 前面的InputStream则是要求文件必须存在.
  • OutputStream也是一个抽象类, 我们想要使用他的方法, 只能使用他的子类FileOutputStream来创建对象
public class demo2 {public static void main(String[] args) throws IOException {try(OutputStream outputStream = new FileOutputStream("./output.txt")){	//打开文件写, 写完后自动关闭文件byte[] bytes = {97, 98, 99};outputStream.write(bytes);  //把字节数组写入文件}catch (IOException e){throw new RuntimeException(e);}}
}

在这里插入图片描述

  • 注意的是, OutputStream写的时候往文件里面写入数据的时候会默认把文件清空. 然后写入.这是操作系统的行为.
  • 如果说我们不想让操作系统每次写入数据的时候都把文件内容清空, 那么我们造创建Filie对象的时候为第二个参数指定true, 意思是以追加方式写入文件, 这样操作系统就不会清空文件了.
    在这里插入图片描述
  • 写入中文字符串
public class demo2 {public static void main(String[] args) throws IOException {try(OutputStream outputStream = new FileOutputStream("./output.txt", true)){String str = "你好中国";byte[] bytes = str.getBytes("utf-8");outputStream.write(bytes);  //把字节数组写入文件}catch (IOException e){throw new RuntimeException(e);}}
}
  • getBytes方法按照指定的字符编码格式转换为一个字节数组(byte[])。

字符流

  • 字节流就是我们读写数据是以字符为单位进行读写.

读(Reader)

  • Reader是抽象类, 如果要使用他的方法, 只能用FileReader即他的子类创建对象从而调用方法.
public class demo3 {public static void main(String[] args) throws IOException {try(Reader reader = new FileReader("./test.txt")){while(true){char[] buffer = new char[1024];int n = reader.read(buffer);    //把从文件中读取的数据放在buffer数组中, 并且返回读取了多少个数据if(n == -1){    //文件内容已经被读取完成break;}for(int i = 0; i < n; i++){System.out.println(buffer[i]);}}}}
}

在这里插入图片描述

  • 字符流在读取的时候会根据文件内容的编码格式进行解码. 这里test文件内容是按utf8编码格式存储的, 那么字符流读取的时候就会按utf8编码要求一样, utf8要求一个字符3个字节. 那么这里就会3个字节为1组读取. 读取完成后会按unicode编码自动解码, 转换成unicode字符. 这个时候buffer就得到了两个unicode编码对应的编码值字符

写(write)

public class demo4 {public static void main(String[] args) throws IOException {try(Writer writer = new FileWriter("./write.txt", true)){writer.write("hello world"); //写入字符串}}
}

在这里插入图片描述

小练习

case1

  • 扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否要删除该⽂件
public class demo5 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入要搜索的目录:");String rootDir = scanner.next();File rootFile = new File(rootDir);if(!rootFile.isDirectory()){System.out.println("输入的不是目录:");return;}System.out.println("请输入关键字:");String keyword = scanner.next();scanDir(rootFile, keyword);}private static void scanDir(File rootFile, String keyword){//列出当前目录的内容File[] files = rootFile.listFiles();if(files == null){return; //当前目录为空, 不可能有包含关键字的文件}//编码目录中的文件for(File file : files){System.out.println("遍历目录&文件: " + file.getAbsolutePath());// 3. 判断当前文件是目录还是普通文件.if(file.isFile()){// 4. 如果是普通文件, 则判断文件名是否包含关键字dealFile(file, keyword);}else{//如果是目录, 递归目录调用本方法scanDir(file, keyword);}}}private static void dealFile(File file, String keyword){if(file.getName().contains(keyword)){System.out.println("发现文件: " + file.getAbsolutePath() + ", 包含关键字! 是否删除? (y/n)");Scanner scanner = new Scanner(System.in);String input = scanner.next();if(input.equalsIgnoreCase("y")){ //忽略大小写file.delete();System.out.println("文件已删除!");}}}
}

case2

  • 进⾏普通⽂件的复制
  • 这里输入必须是绝对路径
    在这里插入图片描述

在这里插入图片描述

public class demo6 {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); //要求destFile不一定存在, 但是destFile所在的目录必须存在// 例如, destFile 为 d:/test/test.txt, 则要求 d:/test 目录存在.if(!destFile.getParentFile().isDirectory()) {System.out.println("目标文件所在目录不存在");return;}// 真正进行复制文件的操作, 读取源文件, 写入复制文件// 此处不应该使用追加写. 需要确保目标文件和源文件一模一样.try(InputStream inputStream = new FileInputStream(srcFile);   //读取源文件OutputStream outputStream = new FileOutputStream(destFile)) //写入复制文件{while(true){byte[] buffer = new byte[1024];int n = inputStream.read(buffer);if(n == -1){break;}// 此处的 write 不应该写整个 buf 数组的.// buf 数组不一定被填满. 要按照实际的 n 这个长度来写入// 读多少, 写多少outputStream.write(buffer, 0, n);}}}
}

case3

  • 扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)
public class demo7 {public static void main(String[] args) throws IOException {Scanner scanner = new Scanner(System.in);System.out.println("请输入要搜索的路径");String rootPath = scanner.next();File rootFile = new File(rootPath);if(!rootFile.isDirectory()){System.out.println("输入的路径不是目录!");return;}System.out.println("请输入要搜索的关键字");String keyword = scanner.next();scanDir(rootFile, keyword);}private static void scanDir(File rootFile, String keyword) throws IOException {File[] files = rootFile.listFiles(); //列出目录if(files == null){//当前目录为空, 不可能有包含关键字的普通文件return;}//遍历当前目录下的所有文件for(File file : files){if(file.isFile()){//是普通文件, 查看文件名是否包含关键字或文件内容是否包含关键字dealFile(file, keyword);}else{scanDir(file, keyword);}}}private static void dealFile(File file, String keyword) throws IOException {if(file.getName().contains(keyword)){System.out.println("文件名包含关键字:" + file.getAbsolutePath());return;}//文件名不包含关键字, 查看文件内容是否包含// 由于 keyword 是字符串. 就按照字符流的方式来处理. 读取出来自动转换unicode字符,StringBuilder stringBuilder = new StringBuilder();try(Reader reader = new FileReader(file)){while(true){char[] chars = new char[1024];int n = reader.read(chars);if(n == -1){ //文件数据已经全部读取完break;}stringBuilder.append(chars, 0, n);}if(stringBuilder.indexOf(keyword) >= 0){ //indexOf查找字符串出现在stringBuilder的位置, 如果大于等于0, 说明包含keywordSystem.out.println("文件内容包含关键字: " + file.getAbsolutePath());}return;}}
}
http://www.dtcms.com/a/350764.html

相关文章:

  • MyBatis 从入门到精通:一篇就够的实战指南(Java)
  • 最大子数组和【栈和分治两种思路】
  • Linux简明教程01 基础运维
  • C标准库 ---- locale.h
  • Escrcpy 3.0投屏控制软件使用教程:无线/有线连接+虚拟显示功能详解
  • 什么是生命体AI
  • TCP和UDP的使用场景
  • 【系统分析师】高分论文:论软件需求验证方法及应用
  • 用蒙特卡洛法求解三门问题和Π
  • day20 二叉树part7
  • 20.14 QLoRA微调Whisper-Large-v2终极指南:3倍速训练+显存直降68%调参秘籍
  • CVPR 2025端到端自动驾驶新进展:截断扩散模型+历史轨迹预测实现精准规划
  • 【工具安装使用-Jetson】Jetson Orin Nano 刷机和踩坑总结
  • 如何在IDEA中使用Git
  • 【嵌入式电机控制#进阶4】无感控制(二):观测器导论锁相环(全网最通俗易懂)
  • WAS/WDF资源文件工具
  • C :结构体对齐
  • vue+vite打包后的文件希望放在一个子目录下
  • Python 并发编程全面指南(多线程 多进程 进程池 线程池 协程和异步编程) 队列
  • 【leetcode】82. 删除排序链表中的重复元素(二)
  • 微算法科技(NASDAQ:MLGO)使用预测分析动态调整区块大小,构建可持续的区块链网络
  • Cursor概述及环境配置
  • 博客园-awescnb插件-geek皮肤异常问题修复
  • Java数据结构——8.优先级队列(堆)(PriorityQueue)
  • SOME/IP-SD报文中 Option Format(选项格式)-理解笔记1
  • 使用 NetworkManager 管理 Wi-Fi 热点
  • 无线USB转换器TOS-WLink网盘更新--TOS-WLink使用帮助V1.0.pdf
  • 管理驾驶舱不是面子工程!一文讲清搭建思路和具体步骤
  • 【Java SE】认识String类
  • B样条基函数:从数学原理到Python实现