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

文件路径、文件系统操作、字节流字符流、文件内容操作、自己实现文件查找 删除 复制、IO报错:拒绝访问

目录

一、什么是文件

文件的分类

文件路径 

二、文件系统操作

四、文件内容操作 

字节流字符流 

1)字节流(二进制文件)

 InputStream概述

 FileInputStream 概述

OutputStream 概述 

2)字符流(文本文件)

五、实现文件查找,删除,复制

根据文件内容查找:

删除:

复制:

IO拒绝访问 


一、什么是文件

文件 就是在计算机的硬盘中躺着的,这些文件都是一个个单独的个体。 

⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数 据⽽存在,我们把这部分信息可以视为⽂件的元信息。

我们文件的存储 是依靠树型结构来存储的 

目录:相当于文件夹,可能很多个文件放一起的

文件:一个单独的个体

文件的分类

即使是普通文件,存储的数据也不尽相同。

所以我们依靠数据的类型,把他们又分为 文本文件 和 二进制文件

文本文件:里面的内容在码表上“有据可查”,能查到对应的 

二进制文件:里面的内容在码表上查不到,就是一堆乱码

啥是码表?

因为计算机只看得懂二进制,所以要把字解析给计算机看的,为了统一,就是根据码表来解析的。

码表也有很多种,最常见的是ASCII码,解析英文字母。但是我们的中文啊,还有其他的特殊字符,就用不了,就需要UTF8或者Unicode字符集等等。

值得注意的是utf8中,一个汉字3个字节。Unicode一个汉字2个字节。

查看字符编码(UTF-8) (mytju.com)

如何分辨是 文本文件 还是 二进制文件呢?  

最简单的办法,就是把文件拖到记事本上:看下图,像png这种的一拖到记事本,就是乱码,所以它是二进制文件。那么剩下的就是文本文件了

文件路径 

我们既然知道了文件的分类,如何找到这个文件呢?那就需要 文件路径 

 文件路径分为 绝对路径 相对路径 

绝对路径:从最早的根目录开始(就是C盘E盘那些),一直到达这个结点

相对路径:可以从任意目录开始(相对这个目录),一直到这个结点

如下,如果要找test.txt这个文件,绝对路径:E:\code\J20240926-FileIO\test.txt

相对路径需要看从哪里出发(.是当前目录        ..是上一级目录)

若从src里面出发:..\test.txt

若从这个界面的路径出发:.\test.txt

二、文件系统操作

我们文件有个类叫File,我们通常是通过这个类来操作文件。

属性

修饰符及类型属性说明
static StringpathSeparator依赖于系统的路径分隔符,String 类型的表⽰
static charpathSeparator依赖于系统的路径分隔符,char 类 型的表⽰

构造⽅法

签名说明
File(File parent, String child)根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例
File(String pathname)根据⽂件路径创建⼀个新的 File 实例,路径可以是绝 对路径或者相对路径
File(String parent, String child)根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实 例,⽗⽬录⽤路径表⽰

 方法

修饰符及返回值类型⽅法签名说明
StringgetParent()返回 File 对象的⽗⽬录⽂件路径
StringgetParent()返回 FIle 对象的纯⽂件名称
StringgetPath()返回 File 对象的⽂件路径
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的⽂件是否真实 存在
booleanisDirectory()判断 File 对象代表的⽂件是否是⼀ 个目录
booleanisFile()判断 File 对象代表的⽂件是否是⼀ 个文件
booleancreateNewFile()根据 File 对象,⾃动创建⼀个空⽂ 件。成功创建后返回 true
booleandelete()根据 File 对象,删除该⽂件。成功 删除后返回 true
voiddeleteOnExit()根据 File 对象,标注⽂件将被删除,删除动作会到 JVM 运⾏结束时 才会进⾏
String[]list()返回 File 对象代表的⽬录下的所有 ⽂件名
File[]listFiles()返回 File 对象代表的⽬录下的所有 ⽂件,以 File 对象表⽰
booleanmkdir()创建 File 对象代表的⽬录
booleanmkdirs()创建 File 对象代表的⽬录,如果必 要,会创建中间⽬录
booleanrenameTo(File dest)进⾏⽂件改名,也可以视为我们平 时的剪切、粘贴操作
booleancanRead()判断⽤⼾是否对⽂件有可读权限
booleancanWrite()判断⽤⼾是否对⽂件有可写权限

 代码如下:

public class demo1 {public static void main(String[] args) throws IOException {File file=new File("./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.getCanonicalPath());}
}//执行结果
.
test.txt
.\test.txt
E:\code\J20240926-FileIO\.\test.txt
E:\code\J20240926-FileIO\test.txt
public class demo2 {public static void main(String[] args) throws IOException {File file=new File("./hello");System.out.println(file.exists());System.out.println(file.isFile());System.out.println(file.isDirectory());System.out.println(file.delete());System.out.println(file.createNewFile());}
}true
false
true
false
false
public class demo3 {public static void main(String[] args) {File file=new File("./hello/ll/qq");System.out.println(Arrays.toString(file.list()));System.out.println(file.mkdirs());}
}[]
false
public class demo4 {public static void main(String[] args) {File srcFile =new File("./test.txt");File descFIle =new File("newTest.txt");srcFile.renameTo(descFIle);}
}

 如何打印目录中的文件呢?

使用递归,把看看是不是目录,里面有没有东西,有的话直接装到一个File[ ]中,然后一个一个打印,遇到目录就继续递归。

public class demo5 {private static void scan(File f) throws IOException {//1.判断是不是目录if(!f.isDirectory()){return;}//2.判断目录内容File[] files=f.listFiles();if(files==null||files.length==0){return;}//3.打印当前目录System.out.println(f.getCanonicalPath());//4.打印文件for(File file:files){if(file.isFile()){System.out.println(file.getCanonicalPath());}else{scan(file);}}}public static void main(String[] args) throws IOException {File file=new File("./");scan(file);}
}

四、文件内容操作 

文件内容操作其实很简单!只需要三步:打开写或读关闭

创建了字节流字符流,就相当于打开了文件,用完之后一定要进行关闭。

为什么操作完文件内容之后,要关闭文件呢?

打开文件,其实是在该进程的文件描述表中,创建了一个新的表项。

文件描述符表:描述了该进程都要操作哪些文件,它可以认为是一个数组,数组的每个元素就是一个结构体文件对象(linux中)每个结构体就描述了对应操作的文件的信息,数组的下标被称为“文件描述符”。

每次打开一个文件,就相当于在数组上,占用的一个位置,而在系统内核中,文件描述符表数组,是固定长度 & 不可扩容的。用一个少一个,如果没了就打开不了文件了。

代码如下:

(推荐使用第二种的语法糖,用起来方便简单吃起来很甜。如果多个就用分号隔开,InputStream下面详讲) 

public class demo7 {//使用finallypublic static void main1(String[] args) throws IOException {InputStream file=null;try {file=new FileInputStream("./test.txt");}catch (IOException e){e.printStackTrace();}finally {try {file.close();}catch (IOException e){throw new RuntimeException();}}}
//第二种使用try with resources,会自动帮你关闭public static void main(String[] args) throws IOException {try(InputStream inputStream=new FileInputStream("./test.txt")) {//....}}
}

而进行写和读,则需要用到字节字符流的一些方法了。 

字节流字符流 

数据流就是计算机对数据的 读取 和 写入 。

为什么叫流呢?

这其实是一个很生动形象的比喻,就像我们接水流100ml,我们可以拿个杯子一次接1ml,接100次,也可以接2ml,接50次.....也可以接100ml,接1次。

所以我们计算机的,可以一次读1个字节,读100次,也可以读2个字节,读50次...也可以读100个字节,读一次。(字符流的话就是读字符)

可以分为两大类:

1)字节流(二进制文件)

 InputStream概述

方法

修饰符及返回值类型⽅法签名说明
intread()读取⼀个字节的数据,返回 -1 代表 已经完全读完了
intread(byte[] b)最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表 以及读完了
intread(byte[] b, int off, int len)最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读 到的数量;-1 代表以及读完了
voidclose()关闭字节流

InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。关于 InputStream 的实现类有很多,基 本可以认为不同的输⼊设备都可以对应⼀个 InputStream 类,我们现在只关⼼从⽂件中读取,所以使⽤ FileInputStream

 FileInputStream 概述

构造方法

签名说明
FileInputStream(File file)利⽤ File 构造⽂件输⼊流
FileInputStream(String name)利⽤⽂件路径构造⽂件输⼊流
public class demo8 {public static void main(String[] args) throws IOException {try (InputStream inputStream = new FileInputStream("./test.txt")) {while (true) {byte[] buffer = new byte[1024];inputStream.read();int n = inputStream.read(buffer);if (n == -1) {break;}for (int i=0;i<n;i++){System.out.printf("0x%x\n",buffer[i]);}}}}
}

这里的buffer是输出型参数,就是被当参数传进去,然后被填满着出来。

就像你去食堂吃饭,把空的盘子给阿姨,阿姨给你抖抖抖,装到你盘子里,然后还给你。

利⽤ Scanner 进⾏字符读取 

上述例⼦中,我们看到了对字符类型直接使⽤ InputStream 进⾏读取是⾮常⿇烦且困难的,所以,我 们使⽤⼀种我们之前⽐较熟悉的类来完成该⼯作,就是 Scanner 类。 

构造方法说明
Scanner(InputStream is, String charset)使⽤ charset 字符集进⾏ is 的扫描读取
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "你好中国" 的内容
public class Main {public static void main(String[] args) throws IOException {try (InputStream is = new FileInputStream("hello.txt")) {try (Scanner scanner = new Scanner(is, "UTF-8")) {while (scanner.hasNext()) {String s = scanner.next();System.out.print(s);}}}}
}
OutputStream 概述 

⽅法 

修饰符及返回值类型方法签名说明
voidwrite(int b)写⼊要给字节的数据
voidwrite(byte[] b)将 b 这个字符数组中的数据全部写 ⼊ os 中
intwrite(byte[] b, int off, int len)将 b 这个字符数组中从 off 开始的 数据写⼊ os 中,⼀共写 len 个
voidclose()关闭字节流
voidflush()重要:我们知道 I/O 的速度是很慢 的,所以,⼤多的 OutputStream 为了减少设备操作的次数,在写数 据的时候都会将数据先暂时写⼊内 存的⼀个指定区域⾥,直到该区域 满了或者其他指定条件时才真正将 数据写⼊设备中,这个区域⼀般称 为缓冲区。但造成⼀个结果,就是 我们写的数据,很可能会遗留⼀部 分在缓冲区中。需要在最后或者合 适的位置,调⽤ flush(刷新)操 作,将数据刷到设备中。

 OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件 中,所以使⽤ FileOutputStream

public class demo9 {public static void main(String[] args) throws IOException {try(OutputStream outputStream=new FileOutputStream("./test.txt",true)) {//            outputStream.write(98);byte[] bytes=new byte[]{98,98,97};outputStream.write(bytes);}}
}

 注意:!!!

这里的OutPutStream它写入的时候,会覆盖文件已有的内容,如果要接着文件内容写,要在FileOutputStream的参数那里,加一个true。

2)字符流(文本文件)

为什么既然都能用,为什么还需要字符流呢?

因为用字节流时,需要我们程序员去记住那些字节对应的东西,如果是中文的话,就需要3个字节,对程序员来说是一件比较麻烦的事情,所以我们直接读字符,也就是字符流。

同理,一个是Reader,一个是Writer,也都是抽象类不能直接实例,而是通过FileReader和FileWrite来实例。 

Reader方法如下: 

 

public class demo10 {public static void main(String[] args) {try (Reader reader = new FileReader("./test.txt")) {
//            int n=reader.read();
//            char ch=(char)n;
//            System.out.println(ch);while (true) {char[] chs = new char[1024];int n=reader.read(chs);if(n==-1){break;}for(int i=0;i<n;i++){System.out.print(chs[i]);}}} catch (IOException e) {e.printStackTrace();}}
}

 Writer方法如下:

public class demo11 {public static void main(String[] args) {try(Writer write=new FileWriter("./test.txt",true)) {write.write("你好世界");} catch (IOException e) {e.printStackTrace();}}
}

五、实现文件查找,删除,复制

根据文件内容查找:

首先先输入它所在的目录,然后看看这个目录有没有错。

没错的话,就输入文件内容的关键字,然后scan搜索递归, 不是目录就返回,把它放到一个File[]里面,空的也返回。

然后reader一下把文件的内容都读到字符串里面,看看有没有包含关键字key。没有的话就下一个,是目录就继续递归。

public class demo14 {public static void main(String[] args) throws IOException {Scanner scanne = new Scanner(System.in);System.out.println("请输入你要搜索的路径");String rootPath = scanne.next();File file = new File(rootPath);if (!file.isDirectory()) {System.out.println("路径有误");return;}System.out.println("请输入关键字");String key = scanne.next();scan(file, key);}private static void scan(File file, String key) throws IOException {if (!file.isDirectory()) {return;}File[] files = file.listFiles();if (files == null || files.length == 0) {return;}for (File f : files) {if (f.isFile()) {doSreach(f, key);} else {scan(f, key);}}}private static void doSreach(File file, String key) throws IOException {StringBuilder stringBuilder = new StringBuilder();try (Reader reader = new FileReader(file)) {while (true) {char[] buffer = new char[1024];int n = reader.read(buffer);if (n == -1) {break;}stringBuilder.append(buffer,0,n);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}if(stringBuilder.indexOf(key)==-1){return;}else{System.out.println("找到了"+file.getCanonicalPath());}}
}

删除:

首先也是输入文件所在的目录, 然后看看这个目录有没有错。

没错的话,就输入文件名字的关键字,然后scan搜索递归, 不是目录就返回,把它放到一个File[]里面,空的也返回。

然后按File[]的内容,for循环找有这个关键字名字的文件,提示用户要不要删除。

public class demo12 {public static void main(String[] args) throws IOException {System.out.println("请输入你要搜索的路径");Scanner scanner=new Scanner(System.in);String rootPath=scanner.next();File file=new File(rootPath);if(!file.isDirectory()){System.out.println("路径不存在");return;}System.out.println("请输入你要删除文件的关键字");String key=scanner.next();scan(file,key);}private static void scan(File currentDir, String key) throws IOException {if(!currentDir.isDirectory()){return;}File[] files=currentDir.listFiles();if(files==null||files.length==0){return;}for(int i=0;i<files.length;i++){if(files[i].isFile()){doDelete(files[i],key);}else {scan(files[i],key);}}}private static void doDelete(File file, String key) throws IOException {if(!file.getName().contains(key)){return;}Scanner scanner=new Scanner(System.in);System.out.println(file.getCanonicalPath()+"是否要删除该文件,Y/n");String s=scanner.next();if(s.equals("Y")||s.equals("y")){file.delete();}}
}

复制:

首先也是输入文件所在的路径, 然后看看这个文件有没有错。

没错的话,就输入你要复制到目标地的路径,如果这时候目标路径的父节点不是目录就不行,因为这个复制是要跟目的地同一个等级。

然后源文件和目的地都没错之后,就可以从源文件中读,然后在目的地中写。

public class demo13 {public static void main(String[] args) {System.out.println("请输入源文件路径");Scanner scanner = new Scanner(System.in);String srcPath = scanner.next();File srcFile = new File(srcPath);if (!srcFile.isFile()) {System.out.println("无此文件");return;}System.out.println("请输入目标文件路径");String descPath = scanner.next();File descFile = new File(descPath);if (!descFile.getParentFile().isDirectory()) {System.out.println("路径有误");return;}try (InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(descFile)) {while (true) {byte[] buffer = new byte[1024];int n = inputStream.read(buffer);if (n == -1) {break;}outputStream.write(buffer,0,n);}} catch (FileNotFoundException ex) {ex.printStackTrace();} catch (IOException ex) {ex.printStackTrace();}}
}

IO拒绝访问 

(在输入目的路径的时候可能会“拒绝访问”报错)

这是因为你没有指定你复制到目的地的名字,只给了路径,还需要给它安一个名字。

如上图,就不会报错了。


http://www.mrgr.cn/news/43265.html

相关文章:

  • 七、Drf版本组件
  • 举例说明 .Net Core 单元测试中 xUnit 的 [Theory] 属性的用法
  • [C++]使用纯opencv部署yolov11-seg实例分割onnx模型
  • 大数据实时数仓Hologres(四):基于Flink+Hologres搭建实时数仓
  • 组合数求法汇总
  • 【前端】前端数据转化为后端数据
  • GPT新功能Canvas!对普通用户最友好的功能!
  • OutputDebugString函数分析
  • 初识数据结构--时间复杂度 和 空间复杂度
  • NX二次开发 遍历图层中的对象UF_LAYER_cycle_by_layer
  • Linux驱动开发常用调试方法汇总
  • 【PyTorch】图像分割
  • 【Linux】详解Linux下的工具(内含yum指令和vim指令)
  • MES系列-MES赋能智能工厂
  • jQuery——事件处理
  • Linux驱动开发(速记版)--热插拔
  • 数据服务-存储服务(NFS)
  • 王者农药更新版
  • 好用的苹果笔推荐!五大高品质王者款!附避坑宝典助你选购无忧!
  • Java中的封装、继承、多态