Java文件IO操作
创始人
2024-05-10 08:53:24
0

目录

一、了解什么是文件

   狭义的文件:

  广义的文件:

二、文件的路径

①文件的绝对路径

②文件的相对路径

三、Java对于文件的操作

    File类的构造方法    

     File类的普通方法

 四、对于文件的内容操作

①FileInputStream(文件输入流)

      常用构造方法:传递一个字符串

       read方法

   (1)无参数的方式:read()

    (2)有参数的版本,参数为一个byte数组

 ②FileOutputStream(文件输出流)

 五、close()方法      

     需要及时关闭"流"的原因:

 六、更加优雅的close()方式

          采用Scanner来读取磁盘的内容:

  七、字符流      


一、了解什么是文件

   文件,File这个概念,在计算机当中,也是非常常见的一个词语。

   狭义的文件:

  指的的是计算机硬盘上面的文件和目录(文件夹)。

   如图:

   


  广义的文件:

 泛指计算机当中的很多的软硬件资源。

  操作系统把很多的硬件设备软件资源抽象成了文件,例如网卡等待...

下面将要重点讨论的,就是狭义的文件


二、文件的路径

       文件的路径,主要是有以下两种表示方式:

①文件的绝对路径

       绝对路径,也比较好理解,可以视为文件相对于某个盘,所存储的位置,一般情况下面,以D:/***/***这样的形式表示。

    例如在上图当中,jdk1.88这个文件夹,它的绝对路径就是:D:\jdk1.88

    

       需要注意的是,虽然在windows当中,现在表示一个文件的目录都是采用“\"作为目录的分隔符的。

       但是,实际上在代码的书写当中不可以采取反斜杠作为路径的分隔符,一般都是采取正斜杠的方式作为分隔符。 因为,反斜杠通常搭配一个普通的字符,都会把"\+某个字符"转义为其他的字符。

       这样,容易引发歧义。因此在代码的书写当中,还是要采取正斜杠"/"的方式。


②文件的相对路径

        相对路径,通常以当前所在目录作为基准,以"."或者".."开头,找到指定的路径。

        举个例子:

        当点击进入了:D:\jdk1.88\lib这个文件夹之后,当前的目录就是:D:\jdk1.88\lib       


       如果想在当前的D:\jdk1.88\lib 目录下面定位到第一个文件夹,也就是missioncontrol。就可以表示为:./missioncontrol

       其中: “./” 就表示当前的目录。


      同理可得:如果当前目录是D:\jdk1.88

      那么,想定位到lib目录,就是:./lib


三、Java对于文件的操作

    分为以下两类:

    1、针对文件的系统操作(创建、删除、重命名等等);

    2、针对文件内容的操作(针对某个文件的读写)。


    下面,首先介绍对于文件的系统操作,需要使用的类为File这个类。

    File类的构造方法    

构造方法说明
File(String pathname)

根据文件的路径创建一个File实例,实例可以是绝对路径,

也可以是相对路径

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

根据父目录+孩子文件路径,创建一个新的File实例,与第2个不同的是,

父目录用路径表示


 其中,第一行的构造方法是最常见的

代码实现:

  File file=new File("D:/bookBook.txt");

 这样,就成功创建出来一个file的实例了。

 需要注意的事项有下面两点:


       ①file对象代表的文件,此时不一定在对应的位置当中存在。如果不存在,可以在后续调用file.mkdir()方法创建。

       如果已经存在了再次调用mkdir()方法创建,那么不会重新创建一个文件,也不会覆盖掉原来已经存在的文件的内容。

       ②如果是单个斜杠,代表创建一个文件,例如(...txt/...doc)

          如果两个及以上的斜杠,代表创建一个文件夹


     File类的普通方法

修饰符及返回
值类型
方法签名 方法签名 
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 FIle 对象的纯文件名称
StringgetPath()返回 File 对象的文件路径
String

 
getAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 File 对象代表的文件是否是一个普通文件
boolean
 
createNewFile()根据 File 对象,自动创建一个空文件。成功创建后返
回 true
booleandelete()根据 File 对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行
String[]list()返回 File 对象代表的目录下的所有文件名
File[]listFiles()返回 File 对象代表的目录下的所有文件,以 File 对象表示
booleanmkdir()创建 File 对象代表的目录
booleanmkdirs()
创建 File 对象代表的目录,如果必要,会创建中间目
booleanrenameTo(File
dest)
进行文件改名,也可以视为我们平时的剪切、粘贴操作
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

 下面,将演示几个常见的普通方法代码实现:

 ①file.getName(String name)

 假设此时文件"bookBook1.txt"已经存在了

 如下面的代码:

 //不一定在D盘当中一定存在这一个路径File file=new File("D:/bookBook.txt");System.out.println(file.getName());

  就会输出bookBook.txt,为对应文件的名称。


如果执行下面的代码:

File file=new File("./bookBook.txt");System.out.println(file.getName());

  也会输出bookBook.txt。 


 ②file.getParent()

File file=new File("D:/bookBook/hello.txt");System.out.println(file.getParent());

  此时,将输出hello.txt的最近一级的目录:即:D:\bookBook 


③file.getPath(),getAbsolutePath()

       此时,将分情况讨论:

       如果file的构造方法当中指定的是一个绝对路径,也就是类似于D:/***/***这样的路径,那么二者输出的时候没有任何差别。

        File file=new File("D:/bookBook/hello.txt");System.out.println(file.getAbsolutePath());System.out.println(file.getPath());

        File file=new File("./hello.txt");System.out.println(file.getAbsolutePath());System.out.println(file.getPath());

        如果file的构造方法当中指定的是一个相对路径,也就是类似于./***这样的路径,那么二者的差别在于:

        file.getAbsolutePatrh()返回的是”绝对路径“,也就是从D盘开始的路径。

        由于此时hello.txt位于idea当中,因此,返回的路径就是当前idea项目的路径+hello.txt

        file.getPath()返回的是这一个文件的”工作路径"。

        运行结果截图:

       


④file.isDirectory(String name)

   输出是否为一个目录。

  如果传递的参数为一个目录,也就是一个文件夹,那么返回true。

  如果传递的参数为一个文件的地址,那么返回false。

        //demo26为一个具体的项目文件夹File file=new File("D:/demo26");//test为一个txt文本文档File file1=new File("./test.txt");//输出trueSystem.out.println(file.isDirectory());//输出falseSystem.out.println(file1.isDirectory());

⑤file.createNewFile:在指定的目录创建一个文件,如果创建成功返回true,否则false

        //test为一个txt文本文档File file1=new File("./test1.txt");//创建成功返回true,创建失败返回falseSystem.out.println(file1.createNewFile());

 同理,file.delete()也是删除一个指定目录的文件。


 四、对于文件的内容操作

       在三当中,提到了对文件内容进行读取操作,那么,下面将介绍对于文件内容的读取操作的一些介绍。

       我们常说的IO流,就是内存和硬盘资的数据交互的一种工具。

       图解:输入流、输出流:

       

 从磁盘读取数据到内存的流,就是输入流------->FileInputStream。

 从内存读取数据到磁盘的流,就是输出流------->FileOutputStream。

 因此,所谓的输入输出流,都是相对于应用程序来讲的。


①FileInputStream(文件输入流)

      常用构造方法:传递一个字符串

       此处的字符串,可以是相对目录,也可以是绝对目录。下面代码采用的是绝对目录的方式

            //如果文件不存在,就会抛出异常FileInputStream inputStream=new FileInputStream("./test.txt");

   需要注意的是,读取的字符串一定要是一个确确实实存在的文件,否则会抛出                  FileNotFoundException


       read方法

        此方法在FileInputStream内部是存在多态的:       

       下面,将简单介绍一下read方法的三个多态形式:


        (1)无参数的方式:read()

           FileInputStream是按照一个一个字节的顺序读取的

           相当于一次只读取一个字节的数据。

           read()方法的返回值却是int类型的。

                 那么它的含义就是,每次只读取一个字节的数据,读取的是它的ASCII码值。

          读取完一个数据之后,再次调用read()方法,会接着读取接下来的一个数据。

          当把整个文件都读取完毕之后,如果继续调用read()方法,那么会直接返回-1.

          代码实现

             

public static void main(String[] args) {try {FileInputStream inputStream= new FileInputStream("./test.txt");while (true){int b=inputStream.read();//当读取到的值为-1的时候,意味着已经读取完毕了,直接跳出循环if(b==-1){break;}//此处需要强制类型转换,才可以读取到对应的真实的字符System.out.print(""+(char)b);}//使用完毕之后,需要手动关闭这个流inputStream.close();} catch (IOException e) {e.printStackTrace();}

     运行结果截图:

         


    (2)有参数的版本,参数为一个byte数组

      byte数组为read读取到的值所传递的数组。

      当第一次调用inputStream.read(byteArray)的时候,会一次性把目标文件当中的所有内容一次保存到byteArray当中,并且返回实际读取的文件的字节数量。

      读取完毕之后,第二次再次读取,会返回-1.


      代码实现:

public static void main(String[] args) {try {//如果文件不存在,就会抛出异常FileInputStream inputStream=new FileInputStream("./test.txt");//read无参数版本:一次读取一个字节byte[] buffer=new byte[1024];while (true){//读取到某一个值,让字符数组对这一个buffer进行读取//尽可能让int len=inputStream.read(buffer);if(len==-1){break;}//遍历buffer数组for(int i=0;i

     

        此时,运行结果为:

        从上往下依次对应hello的ASCII值 


  灵魂拷问:为什么第(2)种方式的效率更高?

       首先需要了解一个前提条件,就是,使用FileInputStream进行IO操作的时候,每IO一次的时间是相同的。

       而第一种方式当中,每循一次,read一次,相当于只IO一次,读取了一次文件,就把所有的内容读取到内存当中了。

       因此,第二种方式减少了IO次数,提高了执行的效率。


 ②FileOutputStream(文件输出流)

       文件专门是把内存当中的数据读取到文件(磁盘)当中。

       也是在构造方法当中指定了需要传输的对应的文件。

OutputStream outputStream=new FileOutputStream("./hello.txt");

       需要注意的是,构造方法当中指定的字符串一定要合法,合法的体现性为字符串一定要以文件目录的形式开头,例如./某某文件这样的格式。或者D:/***/***这样的格式,需要指定文件的目录。


       如果对应的目录下面不存在这个文件,那么会首先创建一个这样的文件出来;


        write()方法

        跟FileInputStream一样,也是存在多态的

       这个write() 方法的操作和read()类似,只是一个输入,一个输出。

       需要注意的是,如果程序启动之前,原来的文件当中仍然有内容,那么,第一次write()的时候,会把原来文件当中的内容全部清空。


 五、close()方法      

       这个方法的含义就是关闭当前的"流”。

       当进行完对应的读写操作之后,应当及时把这个"流"给关闭掉。

       就是调用inputStream.close()或者outputStream.close()。


     需要及时关闭"流"的原因:

        根据前面的知识,我们了解到,进程当中有一个重要的属性,就是文件描述符表,这样的一个"表"。其实相当于一个数组,记录了进程打开了哪些文件。

        一个进程当中的所有线程,共用一个文件描述符表

        每次打开文件的操作,就会在文件描述表当中,申请一个位置,把对应文件的信息存放进去。  每一个被打开了的文件,在内核当中,都是一个file_struct对象。 

        每关闭一个文件,都会把对应的表项释放掉。也就是销毁对应的file_struct对象

        而调用fileInputStream.close()或者fileOutputStream.close(),就相当于上面的"释放"操作。

        如果没有这个操作,那么会造成什么后果呢?

       也就是会让这个file_struct对象一直保留在文件描述符表当中,无法被销毁。这样,会造成极大的内存空间浪费。

       并且,当打开的文件数量越来越多的时候,有可能很快就会让这个"数组"被填满了。也就是当需要再次打开文件的时候,已经无法操作了。

       虽然Java当中有gc垃圾回收机制,会在inputStream或者outputStream被回收的时候释放资源。但是,如果打开的文件太多,有可能gc也来不及释放了。


     


 六、更加优雅的close()方式

       在了解了close()方法的含义之后,可以得出一个结论,就是close()操作一定是在打开文件之后必定进行的一个操作,也就是close()操作是必不可少的。因此,最好把close()操作放在finally代码块当中执行:如下代码:

 FileOutputStream outputStream=null;try {outputStream=new FileOutputStream("./hello.txt");outputStream.write(99);}finally {outputStream.close();}

      这样,就可以让close()操作一定被执行到了。 

      但是,Java当中提供了下面的更加"优雅"的关闭方式:

try (FileOutputStream outputStream = new FileOutputStream("./hello.txt")) {outputStream.write(99);outputStream.write(100);outputStream.write(101);outputStream.write(103);}

     这样,会在write()完所有的内容之后,自动关闭流,释放资源。

     但是,需要注意的是,不是任何一个对象都可以放到try()的括号当中的。

      一定要实现closeable接口:


          采用Scanner来读取磁盘的内容:

           我们通常想从控制台获取输入的时候,会创建Scanner对象:

Scanner scanner=new Scanner(System.in)

            其中,System.in就是一个输入流对象: 

             如果想让Scanner从磁盘当中读取内容,可以考虑这样操作:

public static void main(String[] args) {try (InputStream inputStream=new FileInputStream("./hello.txt")){Scanner scanner=new Scanner(inputStream);//此时读取的内容,就是从hello.txt当中读取的//这里将一次读取全部的内容System.out.println(scanner.next());} catch (IOException e) {e.printStackTrace();}}

           那么这样,读取到的内容就是对应hello.txt文件的全部内容了。

           同时,inputStream对象也已经被关闭了。,也就意味着scanner也被关闭了。 


  七、字符流      

         前面介绍的FileInputStream和FileOutputStream都是字节流,以字节为单位进行读写的。

         下面,将介绍字符流:FileReader以及字节流:FileWriter,以字符为单位进行读写的。

public static void main(String[] args) {try (Writer writer=new FileWriter("./hello.txt")){//写入的时候,如果是数字,那么会转化为对应的ASCII码的字母//如果是’单引号的字符,那么会直接写入单引号的字符writer.write('?');writer.flush();} catch (IOException e) {e.printStackTrace();}}

         当传入的为一个数字的时候,会把它转换为一个字符来进行读写。

   当传入的为一个字符的时候,直接写入一个对应的字符。


         flush方法

        当直接调用writer.write()方法的时候,其实是写入一个缓冲区当中。

        写操作执行完毕之后,内容可能还残留在缓冲区当中,还没有真正进入磁盘当中。

         因此,调用flush()方法,可以确保缓冲区当中的内容被同步到磁盘。

         


 

   

        

     

          

        

        

相关内容

热门资讯

findx耍原生安卓系统,深度... 亲爱的读者们,你是否厌倦了那些花里胡哨的定制系统,渴望回到那个纯净的安卓世界?今天,我要带你一起探索...
一加系统属于安卓系统吗,引领智... 你有没有想过,手机里的那个神奇的“一加系统”到底是不是安卓系统的一员呢?这可是个让人好奇不已的问题哦...
小米2刷安卓系统吗,探索安卓系... 亲爱的读者,你是否曾经对小米2这款手机刷安卓系统的事情感到好奇呢?今天,就让我带你一探究竟,揭开小米...
安卓7.0系统线刷包,深度解析... 你有没有发现,你的安卓手机最近有点儿“蔫儿”了?别急,别急,今天就来给你揭秘如何让你的安卓手机重焕生...
白菜系统和安卓拍照,开启智能生... 你知道吗?最近我在用手机拍照的时候,发现了一个超级酷的功能,简直让我爱不释手!那就是——白菜系统和安...
安卓系统查杀病毒,全方位守护您... 手机里的安卓系统是不是有时候会突然弹出一个查杀病毒的提示?别慌,这可不是什么大问题,今天就来给你详细...
iso系统与安卓各系统哪个好,... 你有没有想过,手机操作系统就像是我们生活中的不同交通工具,各有各的特色和优势。今天,咱们就来聊聊这个...
中柏怎么换安卓系统,解锁更多可... 你有没有发现,中柏的安卓系统有时候用起来还挺不顺手的?别急,今天就来手把手教你如何给中柏手机升级安卓...
安卓热点绕过系统验证,揭秘操作... 你是不是也遇到过这种情况?手机里的安卓热点突然不灵光了,系统验证总是跳出来,让人头疼不已。别急,今天...
安卓系统怎么关闭小艺,安卓系统... 亲爱的安卓用户们,你是否也和我一样,对手机里的小艺助手有些爱恨交加呢?有时候,它贴心得让人感动,有时...
安卓系统计划软件推荐,精选计划... 你有没有发现,手机里的安卓系统越来越智能了?这不,最近我可是挖到了一些超棒的安卓计划软件,它们不仅能...
收钱吧安卓系统插件,便捷支付新... 你有没有发现,现在的生活越来越离不开手机了?手机里装满了各种应用,而今天我要跟你聊聊一个特别实用的工...
鸿蒙系统是否还属于安卓,独立于... 你有没有想过,那个在我们手机上默默无闻的鸿蒙系统,它到底是不是安卓的“亲戚”呢?这个问题,估计不少手...
安卓系统手机用什么钱包,轻松管... 你有没有想过,你的安卓系统手机里装了那么多应用,但最离不开的,可能就是那个小小的钱包了。没错,就是那...
安卓系统能玩部落冲突吗,部落冲... 你有没有想过,安卓系统上的手机,是不是也能玩那款风靡全球的《部落冲突》呢?这款游戏自从推出以来,就吸...
智能机器人安卓系统,引领未来智... 你知道吗?在科技飞速发展的今天,智能机器人已经不再是科幻电影里的专属了。它们正悄悄地走进我们的生活,...
华为win10系统改装安卓系统... 你有没有想过,你的华为笔记本电脑里的Windows 10系统,能不能来个华丽变身,变成安卓系统呢?这...
旧电脑上安什么安卓系统,适配不... 你那台旧电脑是不是已经闲置好久了?别让它默默无闻地躺在角落里,给它来个华丽变身吧!今天,就让我来告诉...
安卓app语言跟随系统,随系统... 你知道吗?在手机世界里,有一个神奇的小功能,它就像你的贴身翻译官,无论你走到哪里,都能帮你轻松应对各...
惠城安卓系统降级在哪,揭秘降级... 你有没有遇到过手机系统升级后,发现新系统让你头疼不已,想回到那个熟悉的安卓系统呢?别急,今天就来告诉...