Java文件IO操作

news2025/1/20 16:28:34

目录

一、了解什么是文件

   狭义的文件:

  广义的文件:

二、文件的路径

①文件的绝对路径

②文件的相对路径

三、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");

        //输出true
        System.out.println(file.isDirectory());
        //输出false
        System.out.println(file1.isDirectory());

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

        //test为一个txt文本文档
        File file1=new File("./test1.txt");

        //创建成功返回true,创建失败返回false
        System.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<len;i++){
                    System.out.println(buffer[i]);
                }
            }
            //使用完毕之后,需要手动关闭这个流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

     

        此时,运行结果为:

        从上往下依次对应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()方法,可以确保缓冲区当中的内容被同步到磁盘。

         


 

   

        

     

          

        

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/155103.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ES索引备份还原

ES索引备份还原一、规划二、备份方案一&#xff1a;备份到集群共享目录方案二&#xff1a;备份到HDFSES还原一、规划 es数据出于线上数据安全考虑&#xff0c;对于es已有的索引数据可以进行安全备份&#xff0c;通常可以将es备份到共享文件目录或者一些其它的数据存储的文件系…

Splashtop Personal 安装教程

splashtop Personal 安装教程1. Splashtop Personal 概述2. splashtop Personal 安装步骤2.1 主控端&#xff08;Splashtop Business app&#xff09;2.2 被控端&#xff08;Splashtop Streamer&#xff09;2.3 打开主控端结束语1. Splashtop Personal 概述 Splashtop Persona…

java跳出循环的几种方式

在java中可以使用break、continue、return语句跳出for循环。break用于完全结束一个循环&#xff0c;跳出循环体&#xff1b;continue只是中止本次循环&#xff0c;接着开始下一次循环&#xff1b;return的功能是结束一个方法。 break语句 break用于完全结束一个循环&#xff0…

4.5 集成运放的种类及选择

一、集成运放的发展概述 集成运放自 20 世纪 60 年代问世以来&#xff0c;飞速发展&#xff0c;目前已经历了四代产品。 第一代产品基本沿用了分立元件放大电路的设计思想&#xff0c;采用了集成数字电路的制造工艺&#xff0c;利用了少量横向 PNP 管&#xff0c;构成以电流源…

Axure 原型设计的三步进阶法

平时跟很多同学朋友的交流过程中&#xff0c;对于axure的需要做到怎样&#xff0c;众说纷纭。总结了一下大家的意见&#xff0c;分别有以下几种&#xff1a; 1、掌握基本的搭建方法即可&#xff0c;不需要做交互&#xff1b; 2、既然做就要做到尽善尽美&#xff0c;页面和交互…

【Python百日进阶-数据分析】Day221 - plotly使用日期类型轴的时间序列 2

文章目录九、具有自定义日期范围的时间序列图9.1 使用plotly.express9.2 使用graph_objects9.3 手动设置日期范围十、带范围滑块的时间序列十一、带范围选择器按钮的时间序列十二、按缩放级别自定义刻度标签格式十三、隐藏周末和假期13.1 隐藏正常周末13.2 隐藏周末和指定日期1…

Windows 11关闭系统更新的方法有哪些?

之前问的最多的就是Win10关闭更新的方法&#xff0c;现在轮到了Windows11&#xff0c;下面我们就具体来看看如何关闭Windows11的系统更新。方案一&#xff1a;使用注册表编辑器关闭Win11更新Windows注册表实质上是一个庞大的数据库&#xff0c;存储着各种各样的计算机数据与配置…

Windows系统下Python安装教程

Python安装环境为Windows10系统&#xff08;64&#xff09; 1.Python下载 选择Python官网进行下载&#xff08;Welcome to Python.org&#xff09;&#xff0c;进入网站&#xff0c;点击Downloads&#xff0c;进入下载模块&#xff0c;鼠标指针放到Download&#xff0c;选择Wi…

聚焦行业,2022巨杉客户案例及产品荣获多项殊荣

2022年&#xff0c;巨杉客户实践案例及产品 广受肯定&#xff0c;荣获多项殊荣 荣誉不仅属于巨杉 它源自于每一位客户的信任和支持 感谢每一位客户对巨杉产品的选择和认可 客户创新实践案例 巨杉联合江阴农商行获评爱分析银行数字化创新实践案例 9月&#xff0c;在“2022…

InstallShield 制作INF驱动安装程序

题外话&#xff1a; 使用INF文件制作经过签名的CAT文件可以参考如下博文&#xff1a; https://blog.csdn.net/qq_29729577/article/details/113537243 回归正题&#xff1a; 本例使用InstallShield 2020版本 驱动文件准备 将INF、CAT、SYS等驱动相关文件放至同一目录下&…

【动态内存管理】C语言

前言&#xff1a; 为什么会存在动态内存分配 我们以前学过的开辟空间的方式有两个特点&#xff1a; 1 空间开辟大小是固定的&#xff1b; 2.数组在申明的时候&#xff0c;必须指定数组的长度&#xff0c;它所需要的内存在编译时分配&#xff1b; 但是对于空间的需求&#xff0c…

Qt基于CTK Plugin Framework搭建插件框架--插件通信【注册接口调用】

文章目录一、前言二、插件完善2.1、添加接口文件2.2、添加接口实现类2.3、服务注册&#xff08;Activator注册服务&#xff09;三、接口调用四、接口 - 插件 - 服务的关系4.1、1对14.2、多对14.3、1对多一、前言 通过Qt基于CTK Plugin Framework搭建插件框架–创建插件一文&am…

解决方案|Keithley吉时利源表测试软件的典型应用及案例介绍

数字源表又称源测量单元(SMU)&#xff0c;是数字万用表(DMM)、电压源、实际电流源、电子负载和脉冲发生器的有用功能集成在仪器中&#xff0c;相当于电压源、电流源、电压表、电流表和电阻表的综合体可以作为四象限电压源或电流源提供精确的电压或电流&#xff0c;同时测量电流…

聚类模型(K-means聚类,系统聚类,DBSCAN算法)

所谓的聚类&#xff0c;就是将样本划分为由类似的对象组成的多个类的过程。聚类后&#xff0c;我们可以更加准确的在每个类中单独使用统计模型进行估计、分析或预测&#xff1b;也可以探究不同类之间的相关性和主要差异。聚类和分类的区别&#xff1a;分类是已知类别的&#xf…

Kafka 生产者

Kafka 生产者 生产者就是负责向 Kafka 发送消息的。 生产者业务逻辑 &#xff08;生产者业务逻辑流程&#xff09; 生产者开发示例 一个正常的生产逻辑流程如下&#xff1a; 配置生产者客户端参数及创建相应的生产者实例 构建待发送的消息 发送消息 关闭生产者实例 生…

CSS权威指南(八)基本元素框

文章目录1.基本元素框2.内边距3.边框4.轮廓5.外边距1.基本元素框 文档中每个元素都会生成一个矩形框&#xff0c;我们称之为元素框。这个框体描述元素在文档布局中所占的空间。因此&#xff0c;元素框之间是有影响的&#xff0c;涉及位置和尺寸。 &#xff08;1&#xff09;宽…

如何在 Excel VBA 中插入行

在本文中,我将解释如何使用VBA(Visual Basic for Applications)在Excel中插入行。VBA 是一种编程语言,适用于在Excel和其他Office程序中工作的人员,因此可以通过编写所谓的宏来自动化Excel中的任务。使用VBA编码,我们可以执行Excel中执行的所有大多数任务,就像复制、粘贴…

【手写 Vue2.x 源码】第十六篇 - 生成 render 函数 - 代码拼接

一&#xff0c;前言 上篇&#xff0c;生成 ast 语法树 - 构造树形结构部分 基于 html 特点&#xff0c;使用栈型数据结构记录父子关系开始标签&#xff0c;结束标签及文本的处理方式代码重构及ast 语法树构建过程分析 本篇&#xff0c;使用 ast 语法树生成 render 函数 - 代…

双软认证-深圳市

双软认证是软件企业的认证和软件产品的登记&#xff0c;企业申请双软认证除了获得软件企业和软件产品的认证资质&#xff0c;同时也是对企业知识产权的一种保护方式&#xff0c;更可以让企业享受国家提供给软件行业的税收优惠政策。 想要在这个残酷的市场中生存下去的话&#x…

cc1200 Sub-1 GHz RF Transceivers 开发

一些应用需要定制开发无线串口、指定发送频点、调制方式、加密传输等等&#xff0c;需要使用无线数据的传输场景&#xff0c;需要使用公用频段进行数据传输。一些场景需要使用Sub-1 GHz频点进行数据传输&#xff0c;比如无线串口&#xff0c;其他无线申请&#xff0c;在国内选择…