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

Java 文件io

文章目录

  • 文件
    • 硬盘
    • 文件路径
    • 文件类型
    • 对文件的操作
      • pathSeparator
      • 文件中的方法使用
      • 文件内容的读写 --- 数据流
        • Reader
        • close
        • Writer
        • InputStream
        • OutputStream
    • 案例

文件

  1. 文件是一个广义的概念,可以代表很多东西,比如:操作系统里,会把很多的硬件设备和软件资源都抽象成 ‘’ 文件 ‘’,统一进行管理
    但是大部分情况下,文件都是指硬盘的文件,文件就相当于是针对 ‘’ 硬盘 ''数据的一种抽象

硬盘

  1. 机械硬盘(HDD):适合顺序读写,不适合随机读写,因为磁头随机读写需要时间进行移动
    固态硬盘(SSD):里面都是集成程度很高的芯片(类似于cpu,内存)
    固态硬盘就要比机械硬盘效率高很多
    在这里插入图片描述

文件路径

  1. 文件的方式操作硬盘
    电脑上有很多的文件,这些文件都是通过 ‘’ 文件系统 ‘’ 来进行组织的
    操作系统提供的模块:文件系统
    操作系统中通过目录这样的结构来组织文件,树形结构的方式

路径是重点
3. 路径:使用目录这样的层次结构来描述文件所在的位置

1.绝对路径:以C盘,D盘这样的盘符开头的

2.相对路径需要先指定一个目录,作为基准目录,从基准目录出发,看看沿着什么样的路线能够找到指定文件。此时路径就是相对路径,往往是以 . 或者 … 开头的(. 这种情况可以省略)
. 表示当前目录
… 表示当前目录的上一级目录

例子:
在这里插入图片描述
在这里插入图片描述

文件类型

  1. 从编程的角度来看,文件类型分为两种:
    文本文件
    二进制文件
    在这里插入图片描述
  2. 如何判定一个文件是文本文件还是二进制文件?
    直接打开记事本,如果是乱码就是二进制文件,否则就是文本文件(记事本就是按照字符的方式来展示内容,这个过程会自动查码表)

二进制转utf-8就是记事本中的乱码,如果查到了就显示出来,没有查到就是空白的部分

很多文件都是二进制的,比如.docx,.pptx

文本文件和二进制文件的区分是非常重要的,代码编写的时候,文本文件和二进制文件的编写方式是不同的

对文件的操作

  1. 文件的操作分为两类:对File类进行操作
    文件系统的操作:
    创建文件,删除文件,判定文件是否存在,判定文件类型,重命名…

文件内容的操作:流对象
读文件,写文件

pathSeparator

  1. pathSeparator就是用来跨平台使用的斜杆分割符,pathSeparator是
    在这里插入图片描述
  2. 构造File对象指定路径
    在这里插入图片描述
  3. 当前文件所在的目录就是父目录
    (当前文件前面的所有目录)

文件名 = 前缀 + 扩展名
使用路径构造File对象,一定要把前缀和扩展名都带上

在这里插入图片描述
文件权限:约定了哪个用户可以读,哪个用户可以写

文件中的方法使用

  1. getPath()
import java.io.File;public class Demo1 {public static void main(String[] args) {File file = new File("d:/test.txt");System.out.println(file.getParent());System.out.println(file.getName());System.out.println(file.getPath());System.out.println(file.getAbsoluteFile());System.out.println(file.getAbsolutePath());}
}

在这里插入图片描述
2. 创建文件

import java.io.File;
import java.io.IOException;public class Demo2 {public static void main(String[] args) throws IOException {File f = new File("d:/test.txt");System.out.println(f.exists());System.out.println(f.isDirectory());System.out.println(f.isFile());// 创建文件boolean ret = f.createNewFile();System.out.println("ret = " + ret);System.out.println(f.exists());System.out.println(f.isDirectory());System.out.println(f.isFile());}
}
  1. 删除文件
    deleteOnExit可以解决断电异常关闭的文件,再打开电脑这个文件会恢复出来
import java.io.File;
import java.lang.reflect.Field;public class Demo3 {public static void main(String[] args) throws InterruptedException {File f = new File("d:/test.txt");boolean ret = f.delete();System.out.println("ret = " + ret);// 没有返回值,在进程结束之后删除// 先执行删除但是要等待5s后进程结束才真正删除/*f.deleteOnExit();Thread.sleep(5000);System.out.println("进程结束!");*/}
}
  1. 获取目录中包含的所有文件
    t.list针对的是目录,不能是文件
import java.io.File;
import java.util.Arrays;public class Demo4 {public static void main(String[] args) {File f = new File("d:/");String[] files = f.list();System.out.println(Arrays.toString(files));}
}

在这里插入图片描述
在这里插入图片描述
5. 创建目录

import java.io.File;
import java.lang.reflect.Field;public class Demo5 {public static void main(String[] args) {File f = new File("d:/test/aa/bb/cc");// boolean ret = f.mkdir();// 创建单级目录boolean ret1 = f.mkdirs();// 创建多级目录// System.out.println("ret = " + ret);System.out.println("ret1 = " + ret1);}
}
  1. 重命名文件名
import java.io.File;public class Demo6 {public static void main(String[] args) {// src是源 dest是目标File srcfile = new File("d:/test1.txt");File destfile = new File("d:/test2.txt");// 把源改成目标boolean ret = srcfile.renameTo(destfile);System.out.println("ret = " + ret);}
}

文件内容的读写 — 数据流

  1. 流对象:stream
    在这里插入图片描述
  2. 在标准库中提供了很多读写文件的流对象,有很多类
    这些类可以分为两个大类:
    字节流(二进制文件)
    字符流(文本文件)

在这里插入图片描述
区分输入和输出是站在cpu的角度上的
读 -> 输入
写 -> 输出
在这里插入图片描述

Reader
  1. 无参的read,一次read一个字符
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;// Reader
public class Demo7 {public static void main(String[] args) throws IOException {Reader r = new FileReader("d:/test.txt");// 读取字符while(true){int c = r.read();if(c == -1){System.out.println("读取结束!");break;}char ch = (char)c;System.out.println(ch);}}
}

在这里插入图片描述
read方法的三个版本:
还有对read的返回值是int的解释:
在这里插入图片描述
utf8是三个字节编码的
unicode是两个字节编码的
把多个unicode字符放到一起是很难区分从哪到哪是完整的一个字符
utf8就可以区分这样连续的字符(其实utf8是从unicode演化过来的)
在这里插入图片描述

  1. read(char[] cbuf),一次read多个字符

应该往这个read里传入的是一个空的字符数组,然后由read方法内部,对这个数组内容进行填充

此时的cbuf这个参数,称为 ‘’ 输出型参数 ‘’
(可以理解函数是一个工厂,参数是原材料,返回值是生产的产品,而有时返回值不好表示生产产品,用了这个参数作为生产的产品)
在这里插入图片描述

// read,一次读多个
while(true){char[] cbuf = new char[1024];int n = r.read(cbuf);// n表示读到的字符个数if(n == -1){// 读到了文件末尾break;}System.out.println("n = " + n);for(int i = 0;i < n;i++){System.out.println(cbuf[i]);}
}

这个read会尽可能把cbuf这个数组给填满,如果实际上文件的内容填不满,也没关系,就直接把所有的数据都读出来就好了

这里的while里面加了一个true就是为了反复读多次,如果一次读不完的话
重点掌握前两个方法

close
  1. 使用close方法最主要的作用是释放文件描述符
// 3. 一个文件使用完毕记得 close
r.close();

不close的后果:
在这里插入图片描述
应该使用try finally来执行,保证close可以被执行到
在这里插入图片描述

try {// read,一次读多个while (true) {char[] cbuf = new char[1024];int n = r.read(cbuf);// n表示读到的字符个数if (n == -1) {// 读到了文件末尾break;}System.out.println("n = " + n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}}finally{// 3. 一个文件使用完毕记得 closer.close();}

还有一种更优雅的方式:
try with resources 这个语法的目的就是 ()
定义的变量,会在try代码结束的时候(不管是正常结束,还是抛出异常)都会自动调用其中的close方法

流对象都可以这么写
在这里插入图片描述

try(Reader reader = new FileReader("d:/test.txt")) {// read,一次读多个while (true) {char[] cbuf = new char[1024];int n = reader.read(cbuf);// n表示读到的字符个数if (n == -1) {// 读到了文件末尾break;}System.out.println("n = " + n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}
}
Writer
  1. 最常用的是一次写一个字符串
    write(String str)
  2. Writer默认情况下,会把原有的文件中的内容清空掉,再写入
    在这里插入图片描述
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;public class Demo8 {public static void main(String[] args) {try(Writer writer = new FileWriter("d:/test.txt")){writer.write("我正在学习!");} catch (IOException e) {throw new RuntimeException(e);}}
}
  1. 如果不想清空原有的内容,需要在文件的构造方法中多写入一个参数,此时不会清空原有的内容,会在原有内容的末尾加上新的内容
    append在末尾加上新加的内容
    在这里插入图片描述

在这里插入图片描述

InputStream
  1. read也有三个版本:
    在这里插入图片描述
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class Demo9 {public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("d:/test.txt")) {byte[] cbuf = new byte[1024];int n = inputStream.read(cbuf);System.out.println("n = " + n);for(int i = 0;i < n;i++){System.out.printf("%x\n",cbuf[i]);}} catch (IOException e) {throw new RuntimeException(e);}}
}
OutputStream
  1. OutputStream和Writer类似,都是打开一个文件都会清空原有的内容,新写入的信息就是新的数据
  2. 如果不想要清除原有的文件内容,可以使用追加写的方式,在构造方法中第二个参数传入true
  3. OutputStream只能写入字节数组,不能写入字符数组,需要使用getBytes使字符转为字节
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class Demo10 {public static void main(String[] args) {try(OutputStream outputStream = new FileOutputStream("d:/test.txt",true)) {String s = "你好";outputStream.write(s.getBytes());} catch (IOException e) {throw new RuntimeException(e);}}
}
  1. 把字节流转为字符流 (读)(办法有好几种)
    下面是最简单的方法
    System.in是输入流InputStream中的一种
    System.in -> InputStream

  2. Scanner不仅可以从文件中读,还可以从键盘中读,还可以从网络中读

import java.io.*;
import java.util.Scanner;public class Demo11 {public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("d:/test.txt")) {// 此时scanner是从文件中读取了Scanner scanner = new Scanner(inputStream);// 使用scanner读取后续的数据String s = scanner.next();System.out.println(s);} catch (IOException e) {throw new RuntimeException(e);}}
}
  1. 把字节流转为字符流 (写)
import java.io.*;public class Demo12 {public static void main(String[] args) {try(OutputStream outputStream = new FileOutputStream("d:/test.txt")) {PrintWriter printWriter = new PrintWriter(outputStream);printWriter.printf("hello");} catch (IOException e) {throw new RuntimeException(e);}}
}
  1. 问题:我们写入了字符串,怎么文本中还是空的?
    在这里插入图片描述
    在这里插入图片描述

解决:为了保证数据写入硬盘中,就应该在合适的实际,使用flush方法手动刷新缓冲区,将缓冲区的数据刷新到硬盘上

import java.io.*;public class Demo12 {public static void main(String[] args) {try(OutputStream outputStream = new FileOutputStream("d:/test.txt")) {PrintWriter printWriter = new PrintWriter(outputStream);printWriter.printf("hello");// 确保数据写入到硬盘上printWriter.flush();} catch (IOException e) {throw new RuntimeException(e);}}
}

案例

  1. 目标:扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件(经典的面试题)
    在这里插入图片描述
  2. 写代码的时候,要对用户输入的内容进行合法性检查
import java.io.File;
import java.util.Scanner;public class Demo13 {public static void main(String[] args) {// 1. 输入你要扫描的路径Scanner scanner = new Scanner(System.in);System.out.println("请输入你要扫描的路径: ");String path = scanner.next();// 判定输入的路径是否合法File rootPath = new File(path);if(!rootPath.isDirectory()){// 如果它不是一个目录System.out.println("您当前输入的扫描路径有误");return;}// 2. 让用户输入要查询的关键词System.out.println("请输入要删除文件的关键词: ");String word = scanner.next();// 3. 可以进行递归的扫描了,以刚才的路径为起点进行扫描// 通过这个方法进行递归scanDir(rootPath,word);}private static void scanDir(File rootPath, String word) {// 1.先列出rootPath中所有的文件和目录File[] files = rootPath.listFiles();if(files == null){// 如果当前目录是空目录就直接returnreturn;}// 2. 遍历这里的所有元素,不同的类型做出不同的处理for(File f : files){// 加个日志,方便观察当前递归的执行过程System.out.println("当前扫描的文件 :" + f.getAbsolutePath());if(f.isFile()){// 普通文件 检查文件是否要删除,并执行删除操作checkDelete(f,word);}else{// 目录 递归再去子目录中判定包含的内容scanDir(f,word);}}}private static void checkDelete(File f, String word) {if(!f.getName().contains(word)){// 不必删除,直接结束方法return;}else{// 需要删除System.out.println("当前文件为:" + f.getAbsolutePath() + ",请确定是否要删除(Y/n):");Scanner scanner = new Scanner(System.in);String choice = scanner.next();if(choice.equals("Y") || choice.equals("y")){// 真正删除文件f.delete();System.out.println("删除完毕!");}else{// 如果是其他操作,不一定要是 n,都会取消删除System.out.println("取消删除!");}}}
}
  1. 文个章节就是了解一下api的使用就可以了

文章转载自:

http://6WypvFgC.tfkqc.cn
http://yytQVNBP.tfkqc.cn
http://qOjYxcum.tfkqc.cn
http://jA5GVcqs.tfkqc.cn
http://jAdxDhmW.tfkqc.cn
http://q2sWDMTO.tfkqc.cn
http://NAjzBvMB.tfkqc.cn
http://I80EhTDX.tfkqc.cn
http://bLOFTkj5.tfkqc.cn
http://OlF3XkX3.tfkqc.cn
http://DLwK9hIi.tfkqc.cn
http://W582Rkc1.tfkqc.cn
http://I7b8SrTq.tfkqc.cn
http://8ibkBpsc.tfkqc.cn
http://grsXGOSo.tfkqc.cn
http://xrJ2Uyod.tfkqc.cn
http://az6dyKTu.tfkqc.cn
http://PG0t1OTr.tfkqc.cn
http://C6TRDMbn.tfkqc.cn
http://mfHOzglM.tfkqc.cn
http://dCrUpEqC.tfkqc.cn
http://C1gcyFGf.tfkqc.cn
http://mUDxN2lh.tfkqc.cn
http://XSgKoSfY.tfkqc.cn
http://mGzQsD4K.tfkqc.cn
http://eAbcVajU.tfkqc.cn
http://xxAFSVBT.tfkqc.cn
http://2xDTZyaM.tfkqc.cn
http://vo6rdO2I.tfkqc.cn
http://vZIE83j8.tfkqc.cn
http://www.dtcms.com/a/382895.html

相关文章:

  • 在Android Studio中配置Gradle涉及到几个关键的文件
  • 基于OpenCV的答题卡自动识别与评分系统
  • 贪心算法应用:出租车调度问题详解
  • 【RK3576】【Android14】如何在Android14下单独编译kernel-6.1?
  • FlashAttention(V2)深度解析:从原理到工程实现
  • ​Prometheus+Grafana监控系统配置与部署全解
  • 电路调试过程中辨认LED正负极并焊接
  • ubuntu24.04 缺少libwebkit2gtk-4.0和libssl.so.1.1
  • eslint-config-encode 使用指南
  • MySQL高阶查询语句与视图实战指南
  • 金融数学与应用数学(金融方向)课程重合度高吗?
  • 知识沉淀过于碎片化如何形成体系化框架
  • 第二十篇|SAMU教育学院的教育数据剖析:制度阈值、能力矩阵与升学网络
  • 深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)第十章知识点问答(10题)
  • dockercompose和k8s区别
  • HENGSHI SENSE 6.0技术解密:边缘计算+Serverless架构如何重构企业级BI实时性
  • Delphi - IndyHttpServer接收上传文件
  • 1.linux环境配置+ssh远程连接vscode调试(问题:无法联网,无法共享粘贴板,不满足运行vscode服务器的先决条件)
  • unity导入blender动画
  • 【杂谈】-备份革命:解锁AI时代的“死数据“金矿
  • npm 发布流程——从创建组件到发布到 npm 仓库
  • 单变量单步时序预测 | TCN-GRU时间卷积神经网络结合门控循环单元
  • 分布式协议与算法实战-理论篇
  • 《sklearn机器学习——数据预处理》生成多项式特征
  • XLua教程之入门篇
  • java学习笔记----标识符与变量
  • C7.1:谐振和调谐的含义
  • 代码随想录学习(一)——数组理论基础
  • Windows 平台上基于 MCP 构建“文心一言+彩云天气”服务实战
  • leetcode38(二叉树的最大深度)