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

文件管理与Java操作全解析

 目录

一、认识文件

1.树型结构组织和目录

2.文件路径

二、Java操作文件

1.File概述

1)属性

2)构造方法

3)常用方法

三、数据流

1.FileInputStream

2.InputStream

3.OutputStream

4.Reader

5.Writer


一、认识文件

狭义的文件: 保存在硬盘上的文件。

广义的文件: 操作系统进行资源管理的一种机制。很多的软件/硬件资源,抽象成 "文件" 来进行表示

先来了解一下 狭义上的文件。针对硬盘这种持久化的存储的 I/O 设备,当我们想要进保存数据的时候,往往不是保存一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念。

文件中除了有数据内容之外,还有一部分信息,例如文件名、文件类型、文件大小等并不作为文件的数据而存在,我们把这部分信息可以视为文件的 元信息

1.树型结构组织和目录

同时,随着我呢间越来越多,对于文件的管理就需要尽快的进行处理,对于处理方式也就现在所使用的方式了,所谓的——文件夹或者目录的概念。

这种就是树型结构组织和目录。

2.文件路径

绝对路径:

    从盘符(根节点)出发,逐级表示出来,这种的形式称之为——绝对路径。

    如:D:\Java_cun\练习 从D这个盘符出发

相对路径:

   需要一个明确的一个 "基准路径",再来查找要查找的文件,就称之为——相对路径。

   如:假设基准路径为:D:\Java_cun 那么查找练习这个文件就是:./练习

          假设基准路径为:D:\Java_cun\练习\src  那么查找练习这个文件就是:../练习

「  表示当前所在的目录位置

「 .. 」表示当前所在的路径的上一层路径,相当于是父类


二、Java操作文件

Java中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。这里要注意的是,存在 File 对象,并不代表真实存在该文件。

1.File概述

1)属性

修饰符及类型属性说明
static StringpathSeparator(比如Windows中为 \ )依赖于系统的路径分割符,String类型的表示
static charpathSeparator依赖于系统的路径分割符,char类型的表示

2)构造方法

签名说明
File(File parent,String child)根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)

根据文

件路径常见一个新的 File 实例,路径可以是绝对路径 或 相对路径

File(String parent,String chile)根据 父目录  + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示。

3)常用方法

返回值类型方法签名说明
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 File 对象的 纯文件名称
StringgetPath()返回 File 对象的文件路径(如果file是绝对路径,那么这里就是绝对路径;反之返回的就是相对路径)
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径 (下面的代码会进行演示什么是修饰过的)

演示代码实现:

先对于绝对路径进行操作:

import java.io.File;
import java.io.IOException;public class Demo1 {public static void main(String[] args) throws IOException {File file = new File("D:/Java_cun/练习/h-IO/test.txt");System.out.println(file.getParent()); // 返回 file 这个文件的父目录文件路径System.out.println(file.getName()); // 返回 file 这个文件的存文件名称// 这个getPath() 和前面构造的过程是相关的,当构造的是绝对路径,那么这里返回的就是绝对路径;反之为相对路径System.out.println(file.getPath()); // 返回 file 这个文件对象的文件路径System.out.println(file.getAbsolutePath()); // 返回 file 这个文件对象的绝对路径// 这个getCanonicalPath()方法是存在异常的,需要进行抛出异常System.out.println(file.getCanonicalPath()); // 返回 file 这个对象修饰过的绝对路径}
}

这里要注意的是对于 getCanonicalPath() 这个方法是存在异常的,需要进行特殊处理。

上述的就是代码所展示的结果了。接下来演示一下用相对路径进行演示一下:

import java.io.File;
import java.io.IOException;public class Demo1 {public static void main(String[] args) throws IOException {File file = new File("./test.txt");System.out.println(file.getParent()); // 返回 file 这个文件的父目录文件路径System.out.println(file.getName()); // 返回 file 这个文件的存文件名称// 这个getPath() 和前面构造的过程是相关的,当构造的是绝对路径,那么这里返回的就是绝对路径;反之为相对路径System.out.println(file.getPath()); // 返回 file 这个文件对象的文件路径System.out.println(file.getAbsolutePath()); // 返回 file 这个文件对象的绝对路径// 这个getCanonicalPath()方法是存在异常的,需要进行抛出异常System.out.println(file.getCanonicalPath()); // 返回 file 这个对象修饰过的绝对路径}
}

这里就可以看出区别了,getAbsolutePath()方法呢返回的直接在构造方法中路径前面添加上一个绝对路径,这个路径就是这个项目的项目目录的路径。getCanonicalPath()是进行处理的一个绝对路径,也就将 '.' 进行剔除的路径。


booleanexists()判断 File对象描述的文件是否真实存在
booleanisFile()判断 File对象代表的文件是否是一个普通文件
booleanisDirectory()判断 File对象代表的文件是否是一个目录
booleancreateNewFile()根据 File对象,自动创建一个空文件。成功创阿金后返回 true
import java.io.File;public class Demo2 {public static void main(String[] args) {File file = new File("./test.txt");// 判断这个 file文件对象 是否是真实存在的System.out.println(file.exists());// 判断这个 file文件对象 是否是一个普通文件System.out.println(file.isFile());// 判断这个 file文件对象 是否是一个目录System.out.println(file.isDirectory());}
}

如果运行上述的代码的话,最后输出的都将会是 false,因为当前路径下不存在 test.txt文件。对于创建文件可以选择手动创建或者是使用代码进行创建文件。这里使用代码进行创建:

import java.io.File;
import java.io.IOException;public class Demo2 {public static void main(String[] args) throws IOException {File file = new File("./test.txt");// 注意进行处理异常,这里是存在返回值的,当创建成功就返回true,否则返回falseSystem.out.println(file.createNewFile());// 判断这个 file文件对象 是否是真实存在的System.out.println(file.exists());// 判断这个 file文件对象 是否是一个普通文件System.out.println(file.isFile());// 判断这个 file文件对象 是否是一个目录System.out.println(file.isDirectory());}
}

在创建成功后,当前项目目录下就会创建一个test.txt文件:

因为这里创建的是一个文件而非目录,所以对于目录的判断即为 false。 


booleandelete()根据 File对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()根据 File对象,标注文件将被删除,删除这个动作会到 JVM  运行结束时才会进行
import java.io.File;public class Demo3 {public static void main(String[] args) throws InterruptedException {File file = new File("./test.txt");System.out.println(file.delete());// 无返回值file.deleteOnExit();// 这里进行睡眠是为了观察 deleteOnExit() 函数的效果Thread.sleep(10000);}
}

        这里 对于这个 deleteOnExit() 函数只有 进程退出时才会删除文件的操作使用场景比如说在 word、ppt中等出现这种情况,比如正在进行编写word的时候写了很多的内容,但是这时候电脑没电了,但是你的文档还没有保存,这时候是不是以为文档没有保存?如果出现这种情况,就会之后,当再次打开word的时候,就会提示你是否恢复未保存的内容,这个就是上述的进程退出时才会删除文件的操作。其实细心就会发现 当你进行操作的时候,offer系列的软件就会产生一个 隐藏的临时文件。


String[]list()返回 File对象代表的目录下的所有文件名
File[]listFiles()返回 File对象代表的目录下的所有文件名,以File对象表示
import java.io.File;
import java.util.Arrays;public class Demo4 {public static void main(String[] args) {File file = new File("C:/");// String类型的数组对象String[] files1 = file.list();System.out.println(Arrays.toString(files1));// File类型的数组对象File[] files2 = file.listFiles();System.out.println(Arrays.toString(files2));}
}

上述的就是输出 C盘 下的所有文件。


import java.io.File;public class Demo5 {public static void main(String[] args) {File file = new File("./test");// 在这个项目目录下创建一个 test目录file.mkdir();File files = new File("./111/222/333");files.mkdirs(); // 创建多级目录}
}

booleanrenameTo(File dest)进行文件改名,也可以视为平时的粘贴操作。还起到 "移动" 效果
import java.io.File;public class Demo6 {public static void main(String[] args) {File file = new File("./test");File newFile = new File("./test2");// 将 file 对象的test 目录的名称修改成 -> test2 这个名称file.renameTo(newFile);}
}

这个就是一个简单的重命名操作,接下来看一下 "移动" 操作:

import java.io.File;public class Demo6 {public static void main(String[] args) {File file = new File("./test");File newFile = new File("./src/test");// 将 test 目录移动到 本项目目录下的 src目录下的test目录下file.renameTo(newFile);}
}

从操作系统的角度上来看,移动操作和重命名本质是一样的。这个移动操作通常来说非常的快,但是也是存在例外的,如果你的操作是跨硬盘了,那么就是相当于是 复制+删除,就非常慢了。


三、数据流

Java中针对文件内容的操作,主要通过一组 "流对象" 来实现的。

因此,计算机中针对 读写文件,使用 流(Stream) 进行表示,流是操作系统层面的术语,和语言是无关的,各种编程语言操作文件,都叫做 —— 流。

Java中提供了一组类来表示流,这里主要进行介绍8个即可。

整体分为:

1.字节流:

        读写文件,以字节为单位,是针对二进制文件使用的。

        InputStream 输入(从文件读数据);OutputStream 输出(往文件写数据)

2.字符流:

        读写文件,以字符为单位。是针对文本文件使用的。

        Reader 输入(从文件读数据);Writer 输出(往文件写数据)

字节是不等于字符的,一个字符可以对应多个字节,具体取决于编码方式(字符集)。

数据的流向:

从硬盘 => CPU 输入;从 CPU => 硬盘 输出。


在了解 InputStream(抽象类) 之前,需要先了解它的具体的实现类。对于InputStream的实现类有很多,因为现在只是关心文件的 读取操作,那么使用 FileInputStream类

1.FileInputStream

构造方法:

签名说明
FileInputStream(File file)利用 File构造文件输入流
FileInputStream(String name)利用文件路径构造文件输出流

只需要了解上述的两个方法即可。之后对于InputStream 会使用到这个类。


2.InputStream

修饰符及返回值类型方法签名说明
intread()

读取一个字节的数据,

返回 -1 代表已经完全读完了

intread(byte[] b)

最多读取 b.length 字节的数据到 b中,

返回实际读到的数量;-1 代表读完了

intread(byte[] b,int off,int len)

最多读取 len - off 字节的数据到b中,

放在从 off 开始,返回实际读到的数量;

-1 代表读完了

void

close()关闭字节流

在正式的进行输入操作也就是read之前呢,现将基本的框架编写出来,但是需要注意当在编写InputStream 的时候其中的 close() 函数一定需要进行执行,要不就是所谓的"占着茅坑不拉屎"

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class Demo7 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {}}
}

这个在try后面加上() 的编写方法称之为 —— try with resources 是Java 1.5 引入的语法。

这样编写的 InputStream 代码,执行完 try 这个代码块之后呢,就会自动调用 close() 函数。就如同 多线程中锁的使用似的。

但是需要注意,并不是所有的类都可以放到 try() 中,只有实现了 Closable 接口的时候才能放入。

这样编写好处也有可以在 try() 中创建多个 InputStream 类,只需要在他们中间加入一个 ';' 即可。


接下来先准备好test.txt文件,之后对于这个文件进行 read 操作

对这个文件进行read操作:

read() 一次读一个字节

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class Demo7 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {while(true) {int data = inputStream.read();if (data == -1) {// 读完了break;}System.out.println(data);}}}
}

进行运行后呢,会发现并不是文件中对应的hello,而是一堆数字,但是是没有问题。因为这个数字翻译过来就是hello,而翻译的依据就是 ascii表:可以进入这里查看菜鸟编程——ASCII表


read(byte[] b) 一次读多个字节 

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class Demo7 {public static void main(String[] args) throws IOException {try(InputStream inputStream = new FileInputStream("./test.txt")) {while(true) {byte[] b = new byte[3];// 输出型参数的写法,返回的就是一次读到了多少个字节int n = inputStream.read(b);if(n == -1) {// 文件读完break;}for (int i = 0;i < n;i++) {System.out.println(b[i]);}System.out.println("==========================");}}}
}

每次进行 read 的时候,都会将byte数组尽可能的进行填满,填不满就能填几个是几个,而 read 后所返回的就是读到了多少长度的字节,就是所谓的 输出型参数。

对于后面的这个 read(byte[] b,int off,int len) 函数就是在上面这个函数的基础上添加一个读取长度,不像上面的是尽可能的去填满 byte[] b 函数。


3.OutputStream

对于使用 OutputStream 之前还是如同 InputStream 似的,需要先了解一个实现类 —— FileOutputStream ,对于这个类和 FileInputStream是类似的。

先看看对于 OuputStream 的方法:

修饰符及返回值方法签名说明
voidwrite(int b)写入传入字节的数据
voidwrite(byte[] b)将 b 这个字节数组的数据都进行写入
intwrite(byte[] b,int off,int len)

将 b 这个字节数组中从off 开始的数据 写入,一共写 len个

voidclose()关闭字节流
voidflush()将缓冲区遗留的数据进行刷新,进行写入到文件中

这里还是使用 try() 方式进行编写这个代码,可以保证执行 close() 函数

并且对于 OutputStream 要写入的数据,如果没有存在对应的文件就会进行创建构造方法中编写的文件。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class Demo8 {public static void main(String[] args) throws IOException {try(OutputStream outputStream = new FileOutputStream("./output.txt")) {outputStream.write(99);outputStream.write(98);outputStream.write(97);}}
}

这里传入的可以是 ascii表的值,进行运行就会发现在对应的项目目录下创建了一个 output.txt 文件这里就是上述传入的 ascii码表对应的值:

但是这样的编写方式是存在问题的,当再次写入的时候,那么这个文件就会先清空再将写入的数据放入到文件中,那么想要继续往后链接,那么需要对于这个构造方法进行参数的再次传入一个值:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class Demo8 {public static void main(String[] args) throws IOException {try(OutputStream outputStream = new FileOutputStream("./output.txt",true)) {outputStream.write(99);outputStream.write(98);outputStream.write(97);}}
}

 添加一个 true,这样之后就会进行链接写入。

一次写若干个字节:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class Demo8 {public static void main(String[] args) throws IOException {try(OutputStream outputStream = new FileOutputStream("./output.txt",true)) {byte[] b = {98,97,96};outputStream.write(b);}}
}

4.Reader

对于这个 Reader 接口呢,同样需要使用其实现类,为 —— FileReader这个实现类的构造方法是和上面的两个是相似的。

修饰符及返回值方法签名说明
intread()一次读一个字符
intread(char[] cbuf)读字符数组,几可能得把字符数组给填满,返回实际读到的字符个数
intread(CharBuffer target)

和上面的是相似的,对于这个CharBuffer 就是对于 char[] 数组进行了封装

intread(char[] cbuf,int off,int len)读字符数组,从off 开始的数据 写入,一共写 len个
voidclose()关闭字符流

一次读一个字符,这个进行转换成char,即可: 

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;public class Demo9 {public static void main(String[] args) {try (Reader reader = new FileReader("./test.txt")) {while (true) {int b = reader.read();if (b == -1) {break;}System.out.println((char) b);}} catch (IOException e) {throw new RuntimeException(e);}}
}

一次读多个字符,这里会自动进行转码:

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;public class Demo9 {public static void main(String[] args) {try (Reader reader = new FileReader("./test.txt")) {while (true) {char[] buf = new char[1024];int n = reader.read(buf);if (n == -1) {break;}for (int i = 0; i < n; i++) {System.out.println(buf[i]);}}} catch (IOException e) {throw new RuntimeException(e);}}
}

5.Writer

对于这个 Writer 接口呢,同样需要使用其实现类,为 —— FileWriter这个实现类的构造方法是和上面的是相似的。

直接看方法:

修饰符及返回值方法签名说明
voidwrite(int c)写入传入的数据
voidwrite(String str)往里写 str 这个字符串
voidwrite(char[] cbuf)将 cbuf 这个字符数组的数据都进行写入
voidwrite(char[] cbuf,int off,int len)

将 cbuf 这个字符数组从off 开始的数据 写入,

一共写 len个

voidwrite(String str,int off,int len)

将 str 这个字符串从off 开始的数据 写入,

一共写 len个

voidclose()关闭字符流

其余的就非常的熟悉了,直接演示对于字符串的编写:

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;public class Demo10 {public static void main(String[] args) {try (Writer writer = new FileWriter("./output.txt", true)) {writer.write("Hello World");} catch (IOException e) {throw new RuntimeException(e);}}
}

这里对于 追加写的话,同样是在构造方法的参数中,添加一个true 和上面的 OutputStream 对于追加写的操作是一致的。


感觉文章不错的话,期待你的一键三连哦,你的鼓励就是我的动力,让我们一起加油,顶峰相见。拜拜喽~~我们下次再见💓💓💓💓💓💓💓💓💓💓💓💓   

http://www.lqws.cn/news/552673.html

相关文章:

  • 编译安装detectron2
  • 常用工具库
  • 北大肖臻《区块链技术与应用》学习笔记
  • 智能库室管控系统DW-S306|全国已经规模化应用
  • 微服务项目,启动某服务,编译后就没反应
  • 【JS-6-ES6中的let和const】深入理解ES6中的let和const:块级作用域与变量声明的新范式
  • 【数据标注师】意图标注
  • 力扣网C语言编程题:在数组中查找目标值位置之二分查找法
  • 能否仅用两台服务器实现集群的高可用性??
  • ADVANCED INTELLIGENT SYSTEMS 东京大学仿生人类手指机器人,实现“皮肤”补水!
  • Harbor的安装与使用
  • 基于MFC的遥感图像匹配程序设计
  • Java 识别和处理 HTML 标签内容
  • Solidity学习 - ABI 应用二进制接口
  • 叉车考试真题(含答案)pdf下载
  • 权限提升-工作流
  • React用户交互事件
  • 一款支持多日志器、多级别、多落地方式的同异步日志系统
  • ViewModel 使用总结:普通、Shared 及嵌套 Fragment 场景
  • 栅极驱动器选的好SiC MOSFET高效又安全
  • RabbitMQ-基础篇
  • StarRocks 向量索引如何让大模型“记性更好”?
  • 【Linux】理解进程状态与优先级:操作系统中的调度原理
  • linux安装vscode
  • ABP VNext + 多数据库混合:SQL Server+PostgreSQL+MySQL
  • .NET C# async/定时任务的异步线程池调度方案最大线程数‌ = 处理器核心数 × 250
  • python 文件处理工具(包含文件读写、后缀获取、压缩和解压、文件夹遍历等)
  • C++ STL深度剖析:Stack、queue、deque容器适配器核心接口
  • [Linux]从零开始的STM32MP157移植Ubuntu根文件系统教程
  • 华为云Flexus+DeepSeek征文|基于Dify构建文本/图像/视频生成工作流