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

javaee初阶 文件IO

目录

一.概念

1.树形结构组织 与 目录

2.⽂件路径(Path)

3.数据类型

4.存储与读取

二.File(类)

1.文件操作

2.方法介绍

1>.属性

2>.构造方法

a.File(File parent,String child)

b.File(String pathname)

c.File(String parent,String child)

3>.方法

a. getParent() 与 getName()

b.getAbsolutePath() 与 getCanonicalPath()

c.exists()

d. isDirectory() 与 isFile()

e.createNewFile() 

f.delete() 与 deleteOnExit()

g. list() 与 listFiles()

h. mkdir() 与 mkdirs()

i. renameTo()

(1)介绍:

(2).代码演示

j.canRead() 与 canWrite()

3.文件内容操作

1>:流

2>:两大类派

(1).字节流 

(2).字符流

(3).对应的类

3>:字节流方法

(1).InputStream概述

a. read() 方法

b.read(byte[] b) 方法

c.read(byte[] b,int off,int len)

(2).OutputStream概述

a. write(int b)​编辑

b.write(byte[] b)

c.write(byte[] b,int off,int len)

4>:字符流方法

(1).FileReader概述

(2).FileWriter概述

5>:(重)close 方法

(1).具体介绍

(2).代码实现

6>:scanner 与 system.out.println()

(1).scanner 与 InputStream

(2).PrintWriter 

三.运用

1>:题目一

2>:题目二

3>:题目三


说到文件大家都不陌生吧,基础的简单概念就不说了

一.概念

1.树形结构组织 与 目录

正常情况,一个文件夹里有许多文件,而这些文件又有许多文件,类似于二叉树 一个根节点有许多节点,这些节点又有许多节点,所以称为数型结构组织,可以把文件夹称为目录

2.⽂件路径(Path)

路径:用于描述某个文件/目录所在的位置

(1).绝对路径:从根目录一直到目标所在的文件的路径

比如: qq的文件所在地 D:\Program Files (x86)\Tencent\QQ 就是绝对路径

(2).相对路径:基准路径开始,走哪个路径可以到目标所在地

比如:以  D:\Program Files (x86) 为基准路径,那么 .\Tencent\QQ 就是相对路径

比如:以 D:\Program Files (x86)\Tencent 为基准路径,那么  .\QQ 就是相对路径

(这里 . 表示当前目录,从当前目录开始 ; 相对路径可以写成QQ,省略 .\)

(3).格式:

a. (..)表示当前文件上一级,例如: ..\QQ 表示QQ上一级Tencent目录

b.路径之间的隔离符用 \(反斜杠) 或者 /(正斜杠) 都可以,最好用正斜杠,因为反斜杠你还要处理转义字符

3.数据类型

文件的数据类型有许多种,如:exe jpg 音频文件 视频文件 等等,咱们分为: 文本文件 与 二进制文件,

文本文件:内容是字符串

文件文件:内容是二进制,人眼看是乱码

当我们进行IO操作是,需要确定目标文件是文本文件还是二进制文件,简单办法就是记事本打开,乱码的就是二进制文件,反之就是文本文件

4.存储与读取

文件是存在硬盘上的,而硬盘这种硬件设施上会存在一些寄存器,可以通过操控寄存器进行IO操作,而

硬盘提供了一组控制寄存器的"操作方法",因为复杂性,Java对其进行封装提供了一些API

二.File(类)

位于

1.文件操作

分为两类:

a.文件系统操作: 通过代码,对文件进行 创建 移动 复制 删除 等操作

b.文件内容操作: 读取文件,写入文件

文件系统(扩展知识):文件系统是操作系统的一个子模块,提供了一些方法,而文件资源管理器通过调用这些方法进行 文件创造 复制 移动 删除等操作,但这些方法底层用c实现,java对其进行封装为一个类File供我们使用

2.方法介绍

File类是java.io包下的类,有许多方法管理文件

1>.属性

这里属性 pathSeparator(路径分隔符) 有两种: / (正斜杠)  \ (反斜杠),咱们无脑用 正斜杠即可

2>.构造方法

这里列举最常用的:

a.File(File parent,String child)

根据父亲目录创建file对象,并根据孩子路径创建一个fie对象

    public static void main(String[] args) {// 假设路径 : D:/java/testFile file = new File("d:/java/");File file1 = new File(file,"test");}
b.File(String pathname)

·根据绝对路径创建file对象

        File file = new File("D:/java/test");

·根据相对路径创建file对象

        File file = new File("./test");

这个 . 代表当前程序运行的工作目录,可以点击终端查看基准路径:

c.File(String parent,String child)

以父亲路径与孩子路径创建file对象

        File file = new File("D:/java/","./test");

3>.方法

a. getParent() 与 getName()

·绝对路径演示方法

        File file = new File("D:/java/test");System.out.println(file.getParent());System.out.println(file.getName());

·相对路径演示方法:

        File file1 = new File("./test");System.out.println(file1.getParent());System.out.println(file1.getName());

可以看出,两个路径都运行结果与预期一致

b.getAbsolutePath() 与 getCanonicalPath()

·绝对路径演示方法

        File file = new File("D:/java/test");System.out.println(file.getAbsolutePath());System.out.println(file.getCanonicalPath());

·相对路径演示方法:

        File file1 = new File("./test");System.out.println(file1.getAbsolutePath());System.out.println(file1.getCanonicalPath());

c.exists()

创建file对象的文件路径可以随便填,但file对象对应的文件不一定存在,所以需要判断才能进行IO

每创建test文件:

        File file1 = new File("./test");System.out.println(file1.exists());// false

当我创建test文件后(直接在该文件夹新建-添加即可):

        File file1 = new File("./test");System.out.println(file1.exists());// true
d. isDirectory() 与 isFile()

当test 是文件夹(目录):

        File file1 = new File("./test");System.out.println(file1.isDirectory());// trueSystem.out.println(file1.isFile());// false

当 test 是 普通文件(存数据的文件,eg: txt  jpg 等)

        File file1 = new File("./test.txt");System.out.println(file1.isDirectory());// falseSystem.out.println(file1.isFile());// true
e.createNewFile() 

创建的是"空"普通文件,具体类型取决于 后缀

        File file1 = new File("./test.txt");// 创建 txt 文件file1.createNewFile();File file2 = new File("./photo.jpg");// 创建 jpg 文件file2.createNewFile();

可以在对应目录查看:

f.delete() 与 deleteOnExit()

这里删除表示直接从硬盘删除,不会放入回收站(小心操作!)

        // 删除文件file1.delete();file2.delete();

g. list() 与 listFiles()

现在我的D盘文件目录如下:

先看list 方法:

        File file1 = new File("d:/");// 获取 D 盘下所有目录名称String[] strFile = file1.list();// 因为 list 返回值可能为 nullif(strFile == null)System.exit(-1);for(String str : strFile)System.out.println(str);

listFiles 方法:

        File file1 = new File("d:/");File[] strFile = file1.listFiles();if(strFile == null)System.exit(-1);for(File file : strFile)System.out.println(file.getName());

一般用这个,因为数数组每个元素都可以衔接File类方法

注(重) :

调用原生的 API方法不会永久删除,而会把文件放入盘符,在回收站进行手动删除

调用delete 方法直接进行永久删除,不进入盘符与回收站;

h. mkdir() 与 mkdirs()

mkdir():只能创建一层目录

        File file1 = new File("./aaa");System.out.println(file1.isDirectory());boolean mkdir = file1.mkdir();System.out.println("创造是否成功:>"+mkdir);System.out.println(file1.isDirectory());

我们可以到文件里看是否创建成功:

mkdirs():创建多层目录

        File file1 = new File("./aaa/bbb/ccc/ddd");System.out.println(file1.isDirectory());boolean mkdir = file1.mkdirs();System.out.println("创造是否成功:>"+mkdir);System.out.println(file1.isDirectory());

可以在文件看到:

i. renameTo()

(1)介绍:

    方法功能为 从  源头source 移动到 目的地 dest;

    若父亲路径一样,则重命名;否测进行移动

(2).代码演示

进行改名:

        File source = new File("./aaa");// 创建 aaa 文件source.mkdir();File dest = new File("./bbb");// 因为 父亲路径相同,相当于重命名source.renameTo(dest);

粘贴:

        File source = new File("./aaa");// 创建 aaa 文件source.mkdir();File dest = new File("./演示1/aaa");// 将 aaa 移动到 演示1 里面并重命名 aaasource.renameTo(dest);

j.canRead() 与 canWrite()

每个人对文件的权限不一样,所以提供这样的方法供查看权限

        File dest = new File("./演示1/aaa");boolean retRead = dest.canRead();boolean retWrite = dest.canWrite();System.out.println("是否可读:>"+retRead);// trueSystem.out.println("是否可写:>"+retWrite);//true

3.文件内容操作

1>:流

文件的内容操作无非read 和 write,而操作系统提供的原生read 和 write 的API被java封装为流对象(一组类)

这里的流对象可以理解非常多的read 和 write 操作的集合

2>:两大类派

(1).字节流 

读写时以字节为单位进行操作,适合二进制读写

(2).字符流

读写时以字符为单位进行操作,适合文本读写

(3).对应的类

3>:字节流方法

现在有个txt文件

(1).InputStream概述
a. read() 方法

    public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("./test.txt");// 创建一次 流,相当于打开文件// InputStream 只涉及读操作,outputStream 只涉及写// 使用读操作 read()// 不清楚有多少个元素,所以循环while(true){int n = inputStream.read();if(n == -1)break;// 打印字节最好用 十六进制System.out.printf("%x\n",n);}

b.read(byte[] b) 方法

(1). 输出型参数

(2).代码与截图

    public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("./test.txt");// read() 读硬盘的值,而硬盘的读取速度最慢了// 所以 read() 一次读一个字节太慢了// 一般用这种读取byte[] bytes = new byte[1024];int n = inputStream.read(bytes);// 如果read没读到值,最终会返回 -1,此时程序退出if(n == -1)System.exit(-1);for(int i = 0 ;i < n;i++) System.out.printf("%x\n",bytes[i]);}

c.read(byte[] b,int off,int len)

(1).方法解释

从 off 下标开始 读 len个元素放入byte中,并返回有效元素个数

(2).代码与截图

    public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("./test.txt");byte[] bytes = new byte[3];int n = inputStream.read(bytes,0,3);// 如果read没读到值,最终会返回 -1,此时程序退出if(n == -1)System.exit(-1);for(int i = 0 ;i < n;i++) System.out.printf("%x\n",bytes[i]);}

(2).OutputStream概述

a. write(int b)
    public static void main(String[] args) throws IOException {// 因为每次进行写入,都会清空之前的值接着重新写入// 所以第二个参数给 true,表示追加写OutputStream outputStream = new FileOutputStream("./test.txt",true);// 输入文件存放的数据// 虽然是 int,但取值范围 0-255,超出会忽略outputStream.write(97);outputStream.write(98);outputStream.write(99);outputStream.write(101);outputStream.write(102);}

b.write(byte[] b)

    public static void main(String[] args) throws IOException {// 因为每次进行写入,都会清空之前的值接着重写写入// 所以第二个参数给 true,表示追加写OutputStream outputStream = new FileOutputStream("./test.txt",true);// 一次写入完整的字节数组byte[] bytes = new byte[]{97,98,99,100,101};// 这里不是输出型参数outputStream.write(bytes);}

c.write(byte[] b,int off,int len)

    public static void main(String[] args) throws IOException {// 因为每次进行写入,都会清空之前的值接着重写写入// 所以第二个参数给 true,表示追加写OutputStream outputStream = new FileOutputStream("./test.txt",true);// 一次写入完整的字节数组byte[] bytes = new byte[]{97,98,99,100,101};// 这里不是输出型参数// 从 0下标开始输出 1个元素outputStream.write(bytes,0,1);}

4>:字符流方法

字符流的输出输入和上面介绍都一样,这里就不演示了

(1).FileReader概述

返回值都是int,且读取完会返回 -1

(2).FileWriter概述

5>:(重)close 方法

(1).具体介绍

流对象用完后要主动释放,而设计释放有手动释放 close 与自动释放GC垃圾回收管理器

close:释放申请的数据库连接 网络连接 文件一切非内存资源

GC:回收内存中没有使用的 引用对象

总结:对内存而言,close()释放对外资源,GC释放对内资源

(2).代码实现

实现如下:

    public static void main(String[] args)  {// 因为文件对应的操作会报错,且 最终要及时执行close,所以 try-catch-finallyInputStream inputStream = null;try{inputStream =  new FileInputStream("./test.txt");byte[] bytes = new byte[3];int n = inputStream.read(bytes,0,3);// 如果read没读到值,最终会返回 -1,此时程序退出if(n == -1)System.exit(-1);for(int i = 0 ;i < n;i++) System.out.printf("%x\n",bytes[i]);}catch(IOException e){e.printStackTrace();}finally {// 因为 可能文件描述表满了// 流对象创建失败,此时就不用释放资源if(inputStream != null){// 因为 close 也会抛异常,此时也要处理try{inputStream.close();}catch(IOException e){e.printStackTrace();}}}}

可以看到非常不美观,感觉太乱了,所以优化一下

    public static void main(String[] args)  {try(InputStream inputStream =  new FileInputStream("./test.txt")){byte[] bytes = new byte[3];int n = inputStream.read(bytes,0,3);// 如果read没读到值,最终会返回 -1,此时程序退出if(n == -1)System.exit(-1);for(int i = 0 ;i < n;i++) System.out.printf("%x\n",bytes[i]);}catch(IOException e){e.printStackTrace();}}

而ReentrantLock类里面的无法这样写,因为类中没有实现 closeable接口

6>:scanner 与 system.out.println()

(1).scanner 与 InputStream

通过之前的学习,scanner是输入类,而InputStream也是输入类,那么又什么相似之处吗?

可以看到,scanner参数的 in 其实是个 值为空的InputStream对象,那么就可以主动给InputStream对象,让scanner从该对象读取元素

假设文件有值:我 爱你 1314,那么读取如下:

    public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("./test.txt")){Scanner scanner = new Scanner(inputStream);String a = scanner.next();String b = scanner.next();int c = scanner.nextInt();System.out.println(a+b+c);}catch (IOException e){e.printStackTrace();}}

所以 scanner + InputStream 对象,可以从指定对象读取值

(2).PrintWriter 

PrintWriter 也是一个流中特殊的类,他负责把内容输入到 文件中

代码实现:

    public static void main(String[] args) {try(PrintWriter printWriter = new PrintWriter("./test.txt")){// 这一步与 System.out.println() 很像// 不过一个把值输出到控制台// 另一个把值输出到文件中printWriter.println("我不爱你了");}catch (IOException e){e.printStackTrace();}}

三.运用

文件IO到此就差不多了,接下来做几道题练下手

1>:题目一

扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否要删除该⽂件

public class Demo2 {private static final Scanner scanner = new Scanner(System.in);public static void main(String[] args) {// 1.输入路径与文件System.out.print("请输入要查询寻的目录>:");String rootpath = scanner.next();System.out.print("请输入要查询的文件名称>:");String word = scanner.next();//2. 判断是否合理if(word.isEmpty()){System.out.println("文件名称错误"+word);return;}//3.判断目录是否存在或格式是否错误File file = new File(rootpath);if(!file.isDirectory()){// file 不存在 或者 file 是一个普通文件System.out.println("目录不存在或是普通文件");return;}// 4.开始查找search(file,word);}//因为目录是一个树形结构组织,所以查找用递归private static void search(File file, String word) {// 1.拿到 file 目录下所有文件File[] files = file.listFiles();//判断是否合理if(files == null)return;// 2.遍历每一个 file 对象,进行对应操作for (File newfile : files){// 判断是否为普通文件if(newfile.isFile()){// 进行删除if(newfile.getName().contains(word))trydelete(newfile);}else if(newfile.isDirectory()){// 开始递归继续 向文件内查找search(newfile,word);}else{// 其他情况,这里暂不处理}}}private static void trydelete(File file) {System.out.println("找到了,文件为>:"+ file.getAbsolutePath());int digtal = 3;while(digtal > 0){System.out.println("你还有"+digtal+"确定机会,请确定删除>:(yes / no)>:");String target = scanner.next();if(target.equalsIgnoreCase("no")) {System.out.println("取消删除");break;}digtal--;}if(digtal == 0){file.delete();System.out.println("删除成功");}}
}

2>:题目二

进⾏普通⽂件的复制(目录因为难度暂不考虑)

public class Demo3 {public static void main(String[] args) {// 1.输入 要复制的文件路径Scanner scanner = new Scanner(System.in);System.out.print("请输入要复制的文件路径>:");String sourcepath = scanner.next();// 2.判断合法性File source = new File(sourcepath);if(!source.exists()){System.out.println("复制的文件不存在");return;}if(source.isDirectory()){System.out.println("复制的文件是目录,不是普通文件");return;}// 3.输入 目的地System.out.print("请输入复制的文件目的地>:");String destpath = scanner.next();// 4.判断合法性// 无需判断存在性// 因为目的地的文件无论存在与否,都会进行覆盖或创建操作File dest = new File(destpath);if(dest.exists()){//  判断目标文件的父亲文件是不是目录if(!dest.getParentFile().isDirectory()){System.out.println("⽬标路径已经存在,并且是⼀个⽬录,请确认路径是否正确");return;}if(dest.isFile()){System.out.println("⽬录路径已经存在,是否要进⾏覆盖?y/n");String ans = scanner.next();if (!ans.equalsIgnoreCase("y")) {System.out.println("停⽌复制");return;}}}// 5.开始覆盖 / 创建// 对于输出流对象而言,创建时若文件存在会打开:若不存在,则会创建后打开try(InputStream sourcetread = new FileInputStream(sourcepath);OutputStream destOut = new FileOutputStream(destpath,true) ){while(true){byte[] bytes = new byte[1024];int n = sourcetread.read(bytes);if(n == -1)break;destOut.write(bytes,0,n);}}catch (IOException e){e.printStackTrace();}System.out.println("复制完成");}
}

可以打开对应文件看看

3>:题目三

扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)

public class Demo4 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("输入查询的根目录>:");String rootpath = scanner.next();// 判断是否合法File rootfile = new File(rootpath);if(!rootfile.exists()){System.out.println("根目录不存在");return;}if(!rootfile.isDirectory()){System.out.println("输入的路径不是一个目录");return;}System.out.print("输入查询的关键字>:");String word = scanner.next();// 递归寻找search(rootfile,word);}private static void search(File rootfile, String word) {// 拿到路径下所有文件File[] files = rootfile.listFiles();if(files == null)return;for(File newFile : files){if(newFile.isFile()){tryread(newFile,word);}else if(newFile.isDirectory()){search(newFile,word);}else{// 其他情况}}}private static void tryread(File newFile, String word) {// 1.判断是否在文件名if(newFile.getName().contains(word)){System.out.println("找到了,路径为>:"+newFile.getAbsolutePath());}// 2.判断是否在内容中存在// 这里因为要比较文件内容,所以按照 字符流 读取try(Reader reader = new FileReader(newFile)){StringBuilder stringBuilder = new StringBuilder();while(true){char[] chars = new char[1024];int n = reader.read(chars);if(n == -1)break;stringBuilder.append(chars,0,n);}// 判断是否存在if(stringBuilder.indexOf(word) >= 0){// 找到了System.out.println("找到了,路径为>:"+newFile.getAbsolutePath());}else{// 没找到return;}}catch (IOException e){e.printStackTrace();}}
}

文件就到此先结束了,注意:文件的操作非常危险,写代码实验时注意仔细看是否要删除

如果对你有帮助,点个赞吧!!


文章转载自:

http://Hx2vSUvH.rysmn.cn
http://QFe1u9vp.rysmn.cn
http://vB7mLRfH.rysmn.cn
http://E3Ifx1WH.rysmn.cn
http://5JyFw5T9.rysmn.cn
http://RwnbG4I4.rysmn.cn
http://MDzVvdaI.rysmn.cn
http://CdKiaWTB.rysmn.cn
http://l1icLzky.rysmn.cn
http://Ph583NC0.rysmn.cn
http://lZzpCJ0M.rysmn.cn
http://fYqxYimX.rysmn.cn
http://rlVi3sAF.rysmn.cn
http://vBVnx90C.rysmn.cn
http://jTO3AeZx.rysmn.cn
http://XSlcXIEs.rysmn.cn
http://A68s1bYQ.rysmn.cn
http://GI6J1Pwa.rysmn.cn
http://72ogFm06.rysmn.cn
http://sDUsteVv.rysmn.cn
http://khPAfEme.rysmn.cn
http://ri9pnO8c.rysmn.cn
http://wMOWnyEo.rysmn.cn
http://CHntq2AW.rysmn.cn
http://UAuMsKt3.rysmn.cn
http://gHeB24h3.rysmn.cn
http://foZPDKf2.rysmn.cn
http://kvGklU3a.rysmn.cn
http://Z5RJz6oV.rysmn.cn
http://TePiVVsL.rysmn.cn
http://www.dtcms.com/a/384712.html

相关文章:

  • 如何调整滚珠丝杆的反向间隙?
  • Python项目中的包添加后为什么要进行可编辑安装?
  • daily notes[45]
  • 基于51单片机的蓝牙体温计app设计
  • Git版本控制完全指南
  • 【CSS】一个自适应大小的父元素,如何让子元素的宽高比一直是2:1
  • 前端通过地址生成自定义二维码实战(带源码)
  • Android Doze低电耗休眠模式 与 WorkManager
  • 用 Go 重写 adbkit:原理、架构与实现实践
  • 通过Magisk service.d 脚本实现手机开机自动开启无线 ADB
  • NineData社区版 V4.5.0 正式发布!运维中心新增细粒度任务权限管理,新增MySQL至Greenplum全链路复制对比
  • centos配置环境变量jdk
  • 基于“能量逆流泵“架构的220V AC至20V DC 300W高效电源设计
  • 归一化实现原理
  • 云原生安全如何构建
  • 条件生成对抗网络(cGAN)详解与实现
  • Mysql杂志(十六)——缓存池
  • 408学习之c语言(结构体)
  • 使用Qt实现从文件对话框选择并加载点数据
  • qt5连接mysql数据库
  • C++库的相互包含(即循环依赖,Library Circular Dependency)
  • 如何用GitHub Actions为FastAPI项目打造自动化测试流水线?
  • LVS与Keepalived详解(二)LVS负载均衡实现实操
  • 闪电科创-无人机轨迹预测SCI/EI会议辅导
  • 自动驾驶中的传感器技术48——Radar(9)
  • HDLBits 解题更新
  • Python 自动化测试开发教程:Selenium 从入门到实战(1)
  • 树莓派4B实现网络电视详细指南
  • Docker:在Windows上安装和使用,加速容器应用开发
  • Android中怎么使用C动态库