Java - File类、递归、IO流

File类、递归、IO流

一、File 类

  • 概述

    • java.io.File 是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找、修改、删除等操作。

    • 构造方法

    public static void main(String[] args) {
        //public String getAbsolutePath():返回此File的绝对路径名字符串
    
        //相对路径
        //idea中,java程序,相对路径是相对于项目路径存在的。
        File f = new File("day10//a.txt");
        System.out.println("相对路径的绝对路径:" + f.getAbsolutePath());
        //绝对路径
        File f2 = new File("F:\\study\\code\\Learning\\JavaSE_Plus\\day10\\a.txt");
        System.out.println("绝对路径的绝对路径:" + f.getAbsolutePath());
    
    }
    

    • 常用方法

    • “D:\a.txt” - 只是代表一个路径,不能说就是文件,因为还有可能是文件夹,到时候还要判断。

    • idea中的默认相对路径是项目的路径。

    • 获取当前路径得到的是当初new File对象用的路径。

    • 只能获取文件的大小,不能获取文件夹的大小,因为计算机底层的文件夹本质上也是一个文件,只是在这个文件中标明了它所存放 的文件的信息,就好像一张清单一样,你去获取文件夹的大小并非真实大小。

    • isDirectory() 与 isFile() ,这两个方法如果返回的是false,有两种情况 1 路径不是一个目录;2 路径压根不存在;delete()方法也一样,返回false,有可能是压根没有这个路径。

二、递归

  • 指在当前方法内调用自己的这种现象,使用递归需要明确递归的出口(结束条件)和规律。

  • 向下扩展,然后向上逐一返回,根据终止条件获得最后的值。

  • 递归占用过多的栈内存,尽量不要用

  • 案例 - 通过递归查找java 文件

    public static void findJava(File file) {
            //2.判断不是目录,结束方法
            if (!file.isDirectory()) {
                return;
            }
            //System.out.println(file.getAbsolutePath());
            //3.是目录,获取目录下所有的File对象
            File[] files = file.listFiles();
    
            //4.遍历所有的File对象
            for (File file1 : files) {
                //5.判断是否是目录
                //	是目录  递归调用(规律)
                if (file1.isDirectory()) {
                    findJava(file1);
                } else if (file1.isFile() && file1.getName().endsWith(".java")) {
                    //  是文件   判断是否是java文件,打印文件名(出口)
                    //System.out.println(file1.getName());
                    System.out.println(file1.getAbsolutePath());
                }
            }
        }
    

三、IO流

  1. IO 流概述

  2. 字节流

    • 概述

    • 字节输出流写出数据

    • 字节输出流追加写入

    • 字节输出流写出换行

    • 字节输入流读取数据

    • 为什么不能一次读取完在全部写出呢?因为内存有限,读取压力大,耗时,而且要读出来才能写出。

    • 案例 - 将已存在的图片,从一个目录中,复制到另一个目录中。

    public static void main(String[] args) throws IOException {
        //需求 将已存在的图片,从一个目录中,复制到另一个目录中。
    
        //字节输入流对象
        FileInputStream fis = new FileInputStream("day10\\image.jpg");
        //字节输出流对象
        FileOutputStream fos = new FileOutputStream("day10\\imageCopy.jpg");
    
        //字节数组读写数据(复制)
        byte[] bys = new byte[8192]; //字符数组每次读取大小建议设为 8192 或者8192的整数倍,len表示实际读到的个数,bys表示读到的内容
        int len = -1;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }
    
        //关流
        fis.close();
        fos.close();
    }
    
    • 注意:路径不存在 创建字节输出流对象会报错

    • 注意:创建一个流对象时,必须传入文件路径,且该路径下,如果没有该文件,会抛出文件不存在异常。

    • 输入输出看的角度是内存(缓存),从硬盘读入到内存,从内存写出到内存

    • flush:刷新(将内存数据刷出到指定路径) 如果内存中有数据,就刷到路径中;close 底层会调用 flush ,但是有的时候还是要自己单独调用flush,因为close一调用就没法用了

    • 读取的量太大,每读一部分都要flush 一下,确保每一段都正常写进去了

    • 字节流输出流 - 写出换行,用字节输出流写出字符串,字符串需要调用getByte()方法转换成字节数组才能正常写出

    • 两个 read 方法

​ ~ 上一个int 返回的是ASCII码,比如字母a,读出来是97,需要转换才能看到a,-1表示没读到数据;第二个方法返回的int ,-1也表示没读到数据。

​ ~ 读取要注意的问题

​ ~ 这样写,每次只能读取2个数据,再读的话会把之前的覆盖,比如abc,第一次是ab,第二次会是cb,c把a覆盖了。

​ ~ 正确用法

  1. 字符流

    • 概述

    • 字符输出流写出数据

    • 字符输出流追加写入

    • 字符输入流读取数据

    • 用字节流复制文本还是没啥问题的,但是如果想把读到的字符比如汉字显示出来,用字节流会显示不全,因为汉字的字节是不固定的,有的2个,有的三个,所以要用到字符流。

    • 字符流是对字节流的优化,本质上还是字节流

    • 注意:字符输出流创建对象,路径对应的文件不存在,自动创建。

    • 注意:使用字符输出流写数据,必须执行刷新操作。

    • 注意:该文件或文件父路径不存在,会抛出文件不存在异常。

    • 案例 - 复制文本

      public static void main(String[] args) throws IOException {
          //注意:字符流只能复制字符(文本)数据
      
          //输入流
          FileReader fr = new FileReader("day10\\a.txt");
          //输出流
          FileWriter fw = new FileWriter("day10\\b.txt");
      
      
          //字符读/写
          //int ch = -1;
          //while ((ch = fr.read()) != -1) {
          //    fw.write(ch);
          //}
      
          //字符数组读/写
          char[] chs = new char[2];
          int len = -1;
          while ((len = fr.read(chs)) != -1) {
              fw.write(chs, 0, len);
          }
          //关流
          fr.close();
          fw.close();
      
      }
      
  2. IO流扩展

  • JDK7版异常处理 - try with resouce

    <1> 概述

    <2> 可以关闭的对象才能使用

    //try-with-resouce
    //把要关闭的对象放到try() 中
    try(FileInputStream fis = new FileInputStream(""); FileOutputStream fos = new FileOutputStream("")){
        //操作
    }catch (IOException e){
       e.printStackTrace();
    }
    
  • 属性集

    <1> 概述

    <2> 属性集IO相关操作

    ​ 本质是个Map 集合,数据的存储形式是键值对,键和值一般都是String 用于存储配置信息

    <3> 用属性集方法返回的是String 类型的

    <4> 主要是结合IO流创建属性文件,用于写明配置信息

    public static void main(String[] args) throws Exception {
        //字符流相关方法
        //public void load(InputStream inStream): 从字节输入流中读取键值对。
        //public void load(Reader reader):从字符输入流中读取键值对。
    
        //创建属性集对象
        Properties p = new Properties();
    
        //取-读(字节,字符)
        //字节流
        //FileInputStream fis = new FileInputStream("day11\\a.properties");
        //p.load(fis);
        //fis.close();
        //字符流
        FileReader fis = new FileReader("day11\\a.properties");
        p.load(fis);
        fis.close();
    
        Set<String> keys = p.stringPropertyNames();
        for (String key : keys) {
            String value = p.getProperty(key);
            System.out.println(key + "==" + value);
        }
    
    }
    
  • 缓冲流读写数据

    <1> 概述

    <2> 缓冲流的使用

    public static void main(String[] args) throws Exception {
        //字节缓冲流
        //public BufferedInputStream(InputStream in):创建一个新的字节缓冲输入流。
        //public BufferedOutputStream(OutputStream out):创建一个新的字节缓冲输出流。
        //字符缓冲流
        //public BufferedReader(Reader reader):创建一个新的字符缓冲输入流。
        //public BufferedWriter(Writer writer):创建一个新的字符缓冲输出流。
        
        //method1();
        method2();
    
    }
    
    private static void method2() throws IOException {
        FileReader fr = new FileReader("day11\\a.txt");
        BufferedReader br = new BufferedReader(fr);
        FileWriter fw = new FileWriter("day11\\b.txt");
        BufferedWriter bw = new BufferedWriter(fw);
    
        //一次读一个字符
        //int ch = -1;
        //while ((ch=br.read())!=-1){
        //    bw.write(ch);
        //}
    
        //使用字符数组读取数据
        int len =-1;
        char[] chs = new char[8];
        while ((len=br.read(chs))!=-1){
            bw.write(chs,0,len);
        }
    
        //关流  关外面就行了(里面的流会自动关掉)
        br.close();
        bw.close();
    }
    
    private static void method1() throws IOException {
        //字节缓冲流
        FileInputStream fis = new FileInputStream("day11\\a.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);
    
        FileOutputStream fos = new FileOutputStream("day11\\b.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //一次读一个字节
        //int by;
        //while ((by = bis.read()) != -1) {
        //    //System.out.println(by);
        //    bos.write(by);
        //}
        //使用字节数组读取数据
        byte[] bys = new byte[8];
        int len = -1;
        while ((len = bis.read(bys)) != -1) {
            System.out.println(new String(bys, 0, len));
            bos.write(bys, 0, len);
        }
    
        //关流  关外面就行了(里面的流会自动关掉)
        bis.close();
        bos.close();
    }
    

    <3> 缓冲流特有方法

    ​ BufferedReader类:public String readLine(): 读一行文字,读取不到内容,返回null。

    ​ BufferedWriter类:public void newLine(): 写一行行分隔符,由系统属性定义符号。

  • 转换流

    <1> 概述

    ​

    <2> 转换流读写数据

    ​

    <3> 转换流指定编码读写

    ​ ~ 构造方法

    ​ InputStreamReader(InputStream in,String charsetName): 创建指定字符集的字符输入流。

    ​ OutputStreamWriter(OutputStream in,String charsetName): 创建指定字符集的字符输出流。

    <4> 所有编码都包含ASCII 码。ASCII 码国际通用,对那些大家都用的字符都编好了,比如字母,逗号等。

    <5> 转换流是字节流与字符流的桥梁,字节流就是通过转换流得到了字符流,没有转换流也就没有字符流,看它的名字就知道,肯定与字节流与字符流都有关系,原来是它们的桥梁。

    <6> JDK11 可以在创建流的时候可以直接指定编码方式,JDK8 不支持。

    <7> 乱码 - 一个严重的问题

    ​ 读的时候我用UTF-8 去读GBK编码的文件,结果由于不同的编码格式,会出现一些utf-8 没法解码的内容,它就会把那些标识成无效字符,如果这个时候我把这些错误解码的数据写入文件,原本GBK能解码的内容,被这么一搞变成了无效字符,结果GBK也识别不了了,那数据就有问题了,如果源文件是一次性的,那后果很严重!

  • 序列化概述

    <1> 概述

    <2> 序列化流读写数据

    ​

    <3> 序列化注意事项

    <4> 序列化操作 - 把类的对象这种运行时才有的数据存储到文件中,同时也支持读取出来,如果类中某个属性的值不想被序列化,可以用transient 关键字修饰成员变量,那在序列化的时候它的值就会显示成默认值。

    <5> java文件编译后的class 文件不能改动,不然序列化也会失败。

    <6> 序列版本号(class 文件的)要一致才能序列化,每次修改了类,都会生成新的版本号,这是系统给的;你也可以指定下面这句话,我们自己设置好版本号,修改了还是同样的版本号,才能正常序列化。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yrq1biJ1-1661857755986)(C:\Users\ASUS\Desktop\学习笔记\自己\笔记截图\image-20220830145148011.png)]

  • 打印流

    <1> 概述

    <2> 注意事项

  • commons-io 工具包的使用

    <1> 概述

    <2> 工具包使用方法

    ​ 先在模块文件夹中新建一个 lib 文件夹,然后把jar包复制过来,再右键 选择下方的add as library,idea会让你选择jar 包 的生效范围,比如是整个项目还是一个模块,目的是让它跟项目搭建关系,写代码才能使用到。

四、装饰者模式

  1. 概述

  2. 图解

  3. 今天的这些流其实用的就是装饰者模式,这些优化后的流的构造方法其实都需要传入一个基本流对象,本质上还是基本流在干活,这些流需要先创建一个字节流的对象,比如FileInputStream的 ,然后把字节流对象放进这些流的构造方法里,因为他们底层还是要用到基本的字节流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值