JAVA中如何操作文件

文件系统操作

创建文件,删除文件,重命名文件,创建目录.....

文件内容操作

对文件内部的内容进行读写和操作

使用File进行操作系统文件

这个File提供的构造方法

File(String,File),在某个File目录之下创建String

File(String),相对路径或者绝对路径下直接创建

File(String,String)父路径+子路径直接创建

File(URL)统一资源标识符,针对本地文件

File的方法演示:

在创建File对象的时候,我传入的是一个绝对路径E:/Test/test.txt

File.getname会直觉会去到这个文件的名字,

File.getparent会获取到这个文件的父目录

File.getpath获取到的是我传入的路径

File.getabsolutefile获取到的是绝对路径

File.getcanonicalfile获取到的是精修版的路径,如果存在./或者../就会把他省略掉

这里可以看到,当我把路径改成了相对路径的时候,因为我没有指定盘符,所以在这个时候基准路径的是这个文件所在的位置。

Getname获取到的依旧是这个名字,

Getparent获取到的是.

Getpath获取到的就是我传入的路径,传入啥就是啥

Getabsolutefile获取到的就是绝对的路径,带.和..是不会省略的

Getcanonicalfile获取到的就是精修版本会自动省略.和..

File.exist判断这个文件是否存在,在我的电脑中确实有这个文件

File.isDirectory判断这个文件是否是一个目录,很明显,我这个只是一个文件

File.isFille判断这个是否是一个文件,返回true因为我这个确实是一个文件

File.createFIle可以创建一个文件,如果存在,就无法创建,不存在就会自动创建,创建的位置是根据你传入的路径来创建的

使用file.delete,只要指定好路径,就能够直接删除,是立刻删除,当代码允许就马上删除

使用file.deleteOnexist,会在线程正常退出的时候删除,这个应用非常广泛,word,ppt这些基本上都是这样的,在你修改的时候会产生一个隐藏文件,不会说因为突然断电导致你写的全部都没了,只要你是正常关闭的这个隐藏文件就会自动删除。

List和ListFile

首先,我这里传入的只是一个相对路径,当我去调用file.list的时候,他首先会去判断我传入的地址是不是真的存在,如果不是就会直接返回null,在idea中查看源码可以看到

现在传入一个真实存在的地址,哦哈,他返回了什么,是地址吗,不是,这个是数组+内存地址的哈希表示,[java.lang.String表示这个是一个数组类型,后面跟的是哈希值

对比一下程序输出的和我本身有的目录

为什么有些不一样,Java 的file.list()会列出 "系统隐藏文件 / 目录",但文件资源管理器即使开了 "隐藏的项目",也会过滤部分 "受保护的系统文件"(比如$Recycle.Bin、hiberfil.sys这些是 "系统保护的隐藏文件",默认不会显示)。

注意一个点,file.list()的返回值是数组类型,所以返回的单纯只是文字,无法对里面的文件进行下一步读取或者修改

Listfile()

使用file.listfile的时候,返回值是file类型,也就是说我们可以对返回的这些值进行下一步的操作

mkdir和mkdirs

mdkir

目前可以看到是没有Test1211这个文件的,当我执行的时候,它就会去创建这个文件,缺点就是无法创建一个多级文件

Mkdirs

使用mkdirs就可以创建多级文件

会在Test目录下创建111文件在111文件内创建222,222之内创建333

Renameto

从操作系统的角度来看,移动和重命名的本质是一样的,都只是修改了文件的路径,没有真正的搬运文件,只有进行跨盘移动的时候,才会真的进行复制移动文件。

在使用这个的时候,首先需要初始化两个file对象,一个保存改名之前的名字,一个写你要改成的名字,然后把新的名字传入到rename中去就行了。

注意,如果文件已经存在或者改名成和已经存在的文件名字一样,是无效的,我试过了。详情可以看源码

Canread和canwirte

这两很简单,就看你有没有权限进行读写

文件内容操作

JAVA中,主要使用的是"流对象"来操作文件,流(stream)是操作系统层面的术语,不管使用什么语言都是叫做流。

流和水流很像,就比如接水的方式和读取文件的方式是类似的,我可以一次读取100字节,10个,1个,这些都是允许的。

字节流

读写文件以字节为单位,针对2进制文件进行读取的,使用inputstream进行输入,outputstream进行输出。

字符流

读写文件以字符为单位,针对文本进行操作,使用reader进行输入,writer进行输出

输入输出(核心)

指的是数据的流向,硬盘->cpu输入,cpu->硬盘输出。要站在cpu的角度去看问题

记住读取是输入,修改是输出

Inputstream

这里可以看到,这个inputstream是一个抽象类,所以没有办法进行实例化,我们可以使用子类fileinputstream实例化这个对象

在fileinputstream中可以传入相对或绝对路径,甚至可以传入一个file对象

在初始化这个对象的时候,我直接就是传入一个不存在的路径,被抓包了,这个fileinputstream当场就给我抛异常直接就是罢工了

这次我给他传入真正存在的,为什么还是罢工???,是因为我们的流是针对文件进行操作的,这个Test是属于目录,不支持这样的操作,所以必须传入一个具体的文件

现在传入一个正在存在的文件,实例化的过程就相当于打开这个文件,我们只打开,不关闭吗?,肯定是要关闭的,不然就会导致资源泄露的问题。

每当程序打开一个文件就会在文件描述符表中申请一个位表项,由于文件描述符表的长度是有限的,如果你只打开,不关闭,那么就会导致最后文件描述符表的资源全部耗尽,后续打开就会失败虽然说GC对内存的处理已经很高级了,但是GC无法处理文件,需要手动管理。

因为try和finally的作用域不一样,所以只能把inputstream放外面(有点像懒汉模式),为了确保最后的close被执行到,就必须放到finally里面,无论如何最后finally都会被执行这样就确保了不会出现资源泄露的问题

这段代码显然有点丑,如何美化一下呢

Try with resources

这种写法和上面的写法是一模一样的,只不过这个语法糖帮我调用了close方法在出这个try代码块的时候帮我自动关闭文件,防止资源泄露的问题

并不是每个都可以这样写,我们之所以可以这样写,就意味着他必须要实现一个closeable的接口,因为只有这样,JVM才能帮我们自动调用close方法

Read方法

Read()

Read的返回值是int类型的,因为要使用-1来表示字节流的工作结束,每次只会读取一个字节

Read(byte【】 b)

返回值也是int也是使用-1来表示流的结束,一次性读出若干个字节放到参数b中间去。

Read(byte【】b,int off, int len)

同样的道理,这个返回值也是int,也是使用-1来表示流的结束,这里需要注意off是便宜了,代表从哪里开始,len表示长度吗,要读取多少个。

现在我在test.txt中输入了helloworld,那么他们分别会读取出什么

首先是read方法,因为他一次只能读取一个字节,所以要加上一个while循环让他去反复读取,因为前面我说了当他读取到-1的时候表示流结束,所以我们的循环条件就是data1 =inputstream.read !=-1;

翻译读取出来的这段话就是helloworld

8进制是0开头的,16进制是0x开头的

一个字节是等于8个比特位的,一个16进制的数字是4个比特位也就是0.5个字节

Read(byte b)

会输出一个读取到了多少个元素

Read(byte【】b,int off, int len)

也是输出读了多少个

举例子,捡豆子,第一个是看你捡了什么品种,第二三个是看你捡了多少个

Outputstream输出流

Outputstream和前面的inputstream一样,都是属于抽象类,他们本身是无法实例化的所以要实例化他的子类,然后因为他也实现了closeable的接口,所以我们可以使用try()语法糖来交给jvm去帮我们自动关闭这个文件,防止资源泄露

这里有一个需要注意的点,当我们传入一个不存在的路径的时候,这个时候outputstream会自动创建一个文件。

这里的构造方法和前面的一模一样,就不展开详细说了

第一个方法,写入了三个aaa传入的是单个字节所对应的ASCII值

注意:在打开文件的一瞬间会自动清除上次文件里面写的内容,这个是操作系统的特性。

如何解决这个问题,很简单,只需要在一开始的时候,设置追加写就行

设置为true这样就不会删掉你之前写的,会在你写的基础上继续写

第二种

传入一个字符数组,很简单

第三种从某个位置插入

从off位置开始,插入长度为l的字符,注意off+len的长度必须小于数组的长度就行

字符流

Reader和write

Reader

Reader也是抽象类,也实现了closeable接口

和之前的都是一样的只要读到-1就是表示结束,如果想要看到文本,让idea帮你翻译就加(char),不然就不加就行

直接全部都读取出来到char数组里面

第三种

指定位置到某个位置

New string(chars,0,n)输出的是数组中的有效数据

Write

和前面的都一样,是属于抽象类的同时实现了closeable接口,可以使用语法糖

可以看到,这个和那个字节流是非常相似的,基本上操作都一样,要注意如果不想之前写的被操作系统吃掉,就要使用追加模式。

缓冲区

一段内存空间,用来提高程序的速度的,会把你要的提前放到缓冲区让速度更快,类似于之前的三级缓存,都是减少交互提高效率

总结

流对象的使用:

都是先打开,再读写,最后一定要关闭,要注意使用写的时候,如果传入的路径不存在,就会自动创建一个路径,如果不想被操作系统吃掉你之前写的,就要注意设置追加模式。

在使用流对象的时候,要做好区分,是文本还是二进制,再区分读和写,要记住输入和输出是相对于CPU来说的,读是输入,写是输出。

相关推荐
SuperherRo2 小时前
JAVA攻防-FastJson专题&各版本Gadget链&autoType开关&黑名单&依赖包&本地代码
java·fastjson·1.2.24·1.2.47·1.2.62·1.2.80
啊森要自信2 小时前
【C语言】 C语言文件操作
c语言·开发语言·汇编·stm32·单片机
爬山算法2 小时前
Netty(5)Netty的ByteBuf是什么?它与Java NIO的ByteBuffer有何不同?
java·开发语言·nio
司徒轩宇2 小时前
C++ 内存分配详解
开发语言·c++
爱笑的眼睛112 小时前
超越SIFT与ORB:深入OpenCV特征检测API的设计哲学与高阶实践
java·人工智能·python·ai
JH30732 小时前
Java 是值传递:深入理解参数传递机制
java·开发语言·windows
CS创新实验室2 小时前
计算机考研408【操作系统】核心知识点总结
java·linux·考研·计算机·操作系统·408
️停云️2 小时前
C++类型转换、IO流与特殊类的设计
c语言·开发语言·c++
while(1){yan}2 小时前
文件IO的常识
java·开发语言·青少年编程·电脑常识