1.File类的使用

1.1、创建File对象

  • File类创建对象

image-20230810161424731.png

  • 注意

    • File对象可以定位文件和文件夹
    • File封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的
  • 绝对路径:从盘符开始

    File file = new File("D:/code/TestPhotot");
    
  • 相对路径:不带盘符,默认直接直接到当前工程下的目录寻找文件

    File file = new File("Demo/src/data");
    
public class Test {
    public static void main(String[] args) {
        //1.创建File对象(指定文件路径)
        //路径写法:
        //E:\\TestPhoto\\xifu.jpg
        //E:/TestPhoto/xifu.jpg
        File file = new File("E:\\TestPhoto\\xifu.jpg");
        File f = new File("E:"+File.separator+"TestPhoto"+File.separator+"xifu.jpg");//相对安全,可以跨平台使用
        System.out.println(file.length());//输出文件的字节大小
        //2.File常见对象,支持绝对路径,支持相对路径(重点)
        File file1 = new File("E:\\TestPhoto\\jichi.jpg");//绝对路径
        System.out.println(file1.length());
        File file2 = new File("Demo/src/data");//相对路径(当前工程目录下的)
        System.out.println(file2.length());

        //3.File创建文件,可以是文件,也可以是文件夹
        File file3 = new File("E:/TestPhoto");
        System.out.println(file3.exists());//判断文件夹是否存在
    }
}

1.2、常用方法:判断文件类型、获取文件信息

image-20230810161434453.png

public class Test {
    public static void main(String[] args) {
        //1.创建File对象
        File file = new File("E:/TestPhoto/xifu.jpg");
        //2.获取绝对路径
        System.out.println(file.getAbsoluteFile());
        //3.获取文件定义的时候使用的路径
        System.out.println(file.getPath());
        //4.获取文件的名称(带后缀)
        System.out.println(file.getName());
        //5.获取文件的大小:字节个数
        System.out.println(file.length());
        //6.获取文件的最后修改时间
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
        //7.判断是文件还是文件夹
        System.out.println(file.isFile());//true
        System.out.println(file.isDirectory());//false
        //8.判断路径是否存在
        System.out.println(file.exists());

        File f = new File("E:/TestPhoto");
        System.out.println(f.isFile());//false
        System.out.println(f.isDirectory());//true
    }
}

1.3、常用方法:创建文件、删除文件功能

  • File类创建文件的功能

image-20230810161444104.png

  • File类删除文件的功能

image-20230810161450282.png

  • 注意
    • delete方法默认只能删除文件和空文件夹,delete方法删除不走回收站
public class Test {
    public static void main(String[] args) throws Exception{
        File file = new File("Demo/src/data02.test");
        //1.创建新文件,创建成狗true,反之false
        System.out.println(file.createNewFile());//true
        //2.mkdir创建一级目录
        File file1 = new File("E:/TestPhoto/aaa");
        System.out.println(file1.mkdir());//true  【了解即可,不怎么会用,后面使用到的文件也是自动创建好的】
        //3.mkdirs创建多级目录(重点)
        File file2 = new File("E:/TestPhoto/bbb/ccc");
        System.out.println(file2.mkdirs());//true
        //4.删除文件或者空文件夹
        System.out.println(file1.delete());//删除上面刚创建的aaa
        //5.只能删除空文件夹,不能删除非空文件夹
        File file3 = new File("E:/TestPhoto");
        System.out.println(file3.delete());//false
    }
}

1.4、常用方法:遍历文件夹

  • File类的遍历功能

image-20230810161457884.png

  • listFiles方法注意事项:

    • 当文件不存在时或者代表文件时,返回null
    • 当文件对象代表一个空文件夹时,返回一个长度为0的数组
    • 当文件对象是一个由内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中放回
    • 当文件对象是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中放回,包含隐藏文件
    • 当没有权限访问该文件时,返回null
public class Test01 {
    public static void main(String[] args) {
        //1.定位一个目录,获取该目录下一级文件名称并遍历
        File file = new File("E:/TestPhoto");
        String[] list = file.list();
        for (String s : list) {
            System.out.println(s);
        }
        //2.获取目录下一级文件对象并遍历
        File file1 = new File("E:/");
        File[] files = file1.listFiles();
        for (File file2 : files) {
            System.out.println(file2.getName());
        }
    }
}

2.补充:方法递归

2.1、方法递归的形式

  • 概述
    • 递归做为一种算法在程序设计语言中广泛应用
    • 方法调用自身的形式称为方法递归
  • 递归的形式
    • 直接递归:方法自己调用自己
    • 间接递归:方法调用其他方法,其他方法又调回方法自己
  • 递归存在的问题
    • 递归如果没有控制好终止,就会出现递归死循环,导致栈内存溢出现象
public class Test {
    public static void main(String[] args) {
        test();
    }
    public static void test(){
        System.out.println("=========test被执行==========");
        test();//递归,会产生死循环
    }
}

2.2、方法递归的应用、执行流程、递归算法的三个核心要素

【案例】

  • 需求:计算1-n的阶乘的结果,使用递归思想解决
  • 分析
    1. 假如认为存在一个公式:f(n) = 1 X 2 X 3 X 4 X 5 X...(n-1) X n
    2. 公式也就等价于:f(n) = f(n-1) X n
public class Test02 {
    public static void main(String[] args) {
        //计算阶乘
        System.out.println(f(5));
    }
    public static int f(int n){
        if(n == 1){
            return 1;
        }
        return f(n - 1)*n;
    }
}

【递归算法三大要素】

  • 递归的公式:f(n) = f(n-1) * n
  • 递归的终结点:f(1)
  • 递归的方向必须走向终结点

2.3、方法递归的经典案例

【案例】

猴子第一天摘下若干桃子,当即吃了一半,觉得不过瘾,于是又多吃了一个,第二天又吃了前天剩余桃子数量的一半,再多吃一个。后面每天都吃前天剩余桃子数量的一半,再多吃一个,等到第10天的时候发现桃子只有1个了

public class Test04 {
    /**
     *  f(x) - f(x)/2 - 1 = f(x+1)
     *  2f(x) - f(x) -2 = 2f(x+1)
     *  f(x) = 2f(x+1) + 2;
     */
    public static void main(String[] args) {
        System.out.println(f(1));
    }
    public static double f(double n){
        if(n == 10){
            return 1;
        }
        return 2*f(n+1) + 2;
    }
}

2.4、其他形式的方法递归案例

【案例】:文件搜索

public class Test05 {
    public static void main(String[] args) {
        File file = new File("D:/");
        searchFile(file,"wegame.exe");
    }
    /** 创建方法,搜搜某个目录下是否有我要找的文件
     * @Param File dir
     * @Param String fileName
     */
    public static void searchFile(File dir,String fileName){
        //1.判断dir是否是目录
        if(dir!=null && dir.isDirectory()){
            //2.是——获取目录下一级文件对象
            File[] files = dir.listFiles();
            //3.是否存在一级文件对象,随后再开始遍历
            if(files!=null && files.length > 0){
                for (File file : files) {
                    //6.判断当前文件对象是文件还是文件夹
                    if(file.isFile()){
                        //7.判断是否是自己要查找的
                        if(file.getName().equals(fileName)){
                            System.out.println("查找文件的绝对路径为:"+file.getAbsoluteFile());
                            return;
                        }
                    }
                    //8.是文件夹,则递归继续寻找
                    searchFile(file,fileName);
                }
            }
        }else {
            //System.out.println("当前搜索的位置不是文件夹!"+dir.getAbsoluteFile());
        }
    }
}

【案例】

  • 需求:啤酒2元1瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问10块钱可以喝多少啤酒,剩余多少空瓶和盖子
public class Test06 {
    public static int totalNumber;//总共的啤酒数量
    public static int lastCoverNumber;//上一次剩余的盖子数量
    public static int lastBottleNumber;//上一次剩余的瓶子数量
    public static void main(String[] args) {
        buy(10);
        System.out.println("总数量:"+totalNumber);
        System.out.println("剩余的盖子数量:"+lastCoverNumber);
        System.out.println("剩余的瓶子数量:"+lastBottleNumber);
    }
    public static void buy(int money){
        //存了买了几瓶的数据
        int buyNumber = money / 2;
        totalNumber += buyNumber;
        //本轮剩余的盖子数和瓶子数量
        int coverNumber = lastCoverNumber + buyNumber;
        int bottleNumber = lastBottleNumber + buyNumber;
        //吧盖子和瓶子换算成钱
        int allMoney = 0;
        if(coverNumber >= 4){
            allMoney += 2;
        }
        lastCoverNumber = coverNumber%4;
        if(bottleNumber >= 2){
            allMoney += 2;
        }
        lastBottleNumber = bottleNumber%2;

        if(allMoney >= 2){
            buy(allMoney);
        }
    }
}

3.补充:字符集

3.1、常见字符集介绍

  • 字符集基础知识
    • 字符集(Character Set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集又:
      • ASCII字符集
      • GBK字符集
      • Unicode(UTF-8)字符集等
  • ASCII字符集
    • ASCII(American Standard Code For Information Interchange,美国信息交换标准代码):包括了数字、英文、符号
    • ASCII使用1个字节存储一个字符,一个字节是8位,总共可以表示128个字符信息,对于表示英文、数字来说是够用的
  • GBK
    • GBK是中国的码表,包含了几万个汉字等字符,同时也要兼容ASCII编码
    • GBK编码中一个中文字符一般以两个字节的形式存储
  • Unicode字符集
    • 统一码,也叫万国码,是计算机科学领域的一项业界标准
    • UTF-8是Unicode的一种常见编码方式
  • 注意
    • UTF-8编码后一个中文一般以三个字节的形式存储,同时也要兼容ASCII编码表
    • 技术人员都应该使用UTF-8的字符集编码
    • 字符解码时使用的字符集和编码的时使用的字符集必须一致,否则会出现乱码
    • 英文和数字在任何国家的编码中都不会乱码

3.2、字符集的编码、解码操作

  • String编码

image-20230810161515407.png

  • String解码

image-20230810161520439.png

public class Test {
    public static void main(String[] args) throws Exception{
        //1.编码:吧文字转为字节(使用指定的编码)
        String str = "abc马浩楠";
        byte[] bytes = str.getBytes();//默认编码字符集为:UTF-8【英文字节统一为1,UTF-8的中文为:一个字是3
        System.out.println(str.length());
        System.out.println(Arrays.toString(bytes));
        //2.解码:吧字节转为文字(编码前和编码后使用的字符集必须一致,否则乱码)
        String result = new String(bytes);
        System.out.println(result);


        //指定字符集
        System.out.println("======================================");
        byte[] gbks = str.getBytes("GBK");//GBK字符集:英文字母一个为1,中文一个为2
        System.out.println(gbks.length);
        System.out.println(Arrays.toString(gbks));
        //解码
        //String rs = new String(gbks);//默认编码为UTF-8 而转字节的为GBK,乱码
        String rs = new String(gbks,"GBK");
        System.out.println(rs);
    }
}

4.IO流:概述

  • 概述
    • I 表示 input,吧硬盘文件中的数据读入到内存的过程,称之输入,负责读
    • O 表示 output,吧内存中的数据写出到硬盘文件的过程,称之输出,负责写
  • IO流的分类

image-20230810161528957.png

  • 总结流的四大类
    • 字节输入流:以内存为基础,来自硬盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流
    • 字节输出流:以内存为基础,吧内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流
    • 字符输入流:以内存为基础,来自硬盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流
    • 字符输出流:以内存为基础,吧内存中是数据以字符写出到磁盘文件或者网络中去的流称为字符输出流

image-20230810161539227.png

5.IO流:字节流

5.1、字节输入流:每次读取一个字节

image-20230810161544940.png

  • 文件字节输出流:FileInputStream
    • 作用:以内存为基础,吧磁盘文件的数据以字节的形式读取到内存中去

image-20230810161603092.png

public class Test {
    public static void main(String[] args) throws Exception {
        //1.创建一个文件字节流输入流与文件接通
        InputStream is = new FileInputStream("Demo/src/data");
        //2.读取字节并输出
        /*System.out.println((char)is.read());
        System.out.println((char)is.read());
        System.out.println((char)is.read());
        System.out.println((char)is.read());*///文件当前只有3个,所以读取到第四个的时候会返回-1
        //3.使用循环遍历 改进读取
        int b;
        while ((b = is.read()) != -1) {
            System.out.println((char)b);
        }

    }
}
//data:ab1

5.2、字节输入流:每次读取一个字节数组

public class Test02 {
    public static void main(String[] args) throws Exception{
        //1.创建输入流对象与源文件接通
        InputStream is = new FileInputStream("Demo/src/data02");

        //2.读取字符数组,一次读取三个字符
        /*byte[] bytes = new byte[3];
        int count = is.read(bytes); //记录读取字节数
        System.out.println("读取的字节数:"+count);
        String str = new String(bytes);
        System.out.println(str);

        int count1 = is.read(bytes); //记录读取字节数
        System.out.println("读取的字节数:"+count1);
        String str1 = new String(bytes);
        System.out.println(str1);

        int count2 = is.read(bytes); //记录读取字节数
        System.out.println("读取的字节数:"+count2);
        String str2 = new String(bytes);
        System.out.println(str2);

        int count3 = is.read(bytes); //记录读取字节数
        System.out.println("读取的字节数:"+count3);//读取数量为3,但未读的为2个字节,所以最后的一个字节是上一组读取没被覆盖的
        //解决:读取多少出多少
        String str3 = new String(bytes,0,count3);
        System.out.println(str3);*/

        //3.改进,使用循环遍历
        int count;//记录读取数量
        byte[] bytes = new byte[3];//每次读取3个字节
        while((count = is.read(bytes)) > 0){
            System.out.println(new String(bytes,0,count));
        }
    }
}
//data02:abc爱efgbb

【存在问题】

  • 使用字节流读取中文输出乱码,如何不乱吗
    • 定义一个与文件一样大的字节数组,一次性读完文件的全部字节
  • 这样处理是否存在问题
    • 如果文件过大,字节数组可能引起内存溢出【但通常不会说特别大】

5.3、字节输入流:读取文件的全部字节

【方式一】

  • 自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读完

image-20230810161614600.png

【方式二】

  • 官方为字节输入流InputStream提供了API可以直接把文件的全部数据读取到一个字节数组中

image-20230810161620723.png

public class Test03 {
    public static void main(String[] args) throws Exception{
        //1.创建文件字节输入流与源文件接通
        File file = new File("Demo/src/data03");
        InputStream is = new FileInputStream(file);

        //2.定义数组,长度与读取文件大小刚好一致【避免因为文件字节不是3的倍数中遇见中文而乱码】
        /*byte[] bytes = new byte[(int) file.length()];
        int length = is.read(bytes);
        System.out.println("读取字节:"+length);
        System.out.println("文件大小:"+file.length());
        System.out.println(new String(bytes));*/

        //改进:使用Api直接读取全部字节
        byte[] bytes = is.readAllBytes();
        System.out.println(new String(bytes));
    }
}

5.4、字节输出流:写字节数据到文件

  • 文件字节输出流:FileOutputStream
    • 作用:以内存为基础,把内存中的数据以字节的方式写道磁盘文件中

image-20230810161628401.png

  • 写数据出去的API

image-20230810161634899.png

  • 流的关闭与刷新

image-20230810161641179.png

public class Test {
    public static void main(String[] args) throws Exception{
        //1.创建文件字节输出流与目标文件接通
        OutputStream os = new FileOutputStream("Demo/src/out.txt");//每次创建,就会清空该文件之前的东西,再写新数据
        //OutputStream os = new FileOutputStream("Demo/src/out.txt",true);多的参数true:表示不清空之前的东西,继续写新的数据
        //2.写数据出去
        //a.public void write(int a):写一个字节出去
        os.write('a');
        os.write(97);
        os.write("\r\n".getBytes());//换行:单独\n可能导致有些系统不兼容
        //os.write('马');乱码
        //b.public void write(byte[] buffer):写一个字节数组出去
        byte[] buffer = {'a',97,98,99};
        os.write(buffer);
        os.write("\r\n".getBytes());//换行
        //c.public void write(byte[] buffer,int pos,int len):写一个字节数组的一部分出去
        byte[] buffer1 = {'a',97,98,99,100};
        os.write(buffer1,0,3);
        os.write("\r\n".getBytes());//换行
        //写中文
        byte[] buffer2 = "我是中国人".getBytes();
        //byte[] buffer2 = "我是中国人".getBytes("GBK");写出写入不一致,会导致乱码
        os.write(buffer2);
        os.write("\r\n".getBytes());//换行
        //刷新数据:刷新后可以继续使用流
        //os.flush();
        //释放资源,自带刷新数据,但释放资源后,流不能继续使用
        os.close();
    }
}

5.5、文件拷贝

public class Test {
    public static void main(String[] args) {
        try {
            //1.创建字节输入流与文件接通
            InputStream is = new FileInputStream("E:\\TestPhoto\\17dfcc00fc81573fd8e77177768e0502.mp4");
            //2.创建字节输出流
            OutputStream os = new FileOutputStream("E:\\TestPhoto\\copy.mp4");
            //3.定义字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录读取次数
            while((len = is.read(buffer)) != -1){
                //转移数据
                os.write(buffer,0,len);
            }
            System.out.println("复制成功!");
            //关闭流
            os.close();
            is.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6.IO流:资源释放的方式

6.1、try-catch-finally

  • finally:
    • 放在try-catch后面的,无论是正常执行还是异常执行代码,最后一定会执行,除非JVM退出
  • 作用:
    • 一般用于进行最后的资源释放操作
  • 格式
public class Test {
    public static void main(String[] args) {
        InputStream is = null;
        OutputStream os = null;
        try {
            //1.创建字节输入流与文件接通
            is = new FileInputStream("E:\\TestPhoto\\17dfcc00fc81573fd8e77177768e0502.mp4");
            //2.创建字节输出流
            os = new FileOutputStream("E:\\TestPhoto\\copy.mp4");
            //3.定义字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录读取次数
            while((len = is.read(buffer)) != -1){
                //转移数据
                os.write(buffer,0,len);
            }
            System.out.println("复制成功!");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
            try {
                //加上非空校验,以防流并没有找到文件无法产生(避免空指针异常)
                if(os!=null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is!=null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

6.2、简化方式

  • JDK7改进方案

image-20230810161656184.png

public class Way02 {
    public static void main(String[] args) {
        try(
                //这里只能存放资源对象,用完会自动关闭(close),自动释放资源(即使出现异常,也会执行这个操作)
                //1.创建字节输入流与文件接通
                InputStream is = new FileInputStream("E:\\TestPhoto\\17dfcc00fc81573fd8e77177768e0502.mp4");
                //2.创建字节输出流
                OutputStream os = new FileOutputStream("E:\\TestPhoto\\copy.mp4");
                ) {
            //3.定义字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录读取次数
            while((len = is.read(buffer)) != -1){
                //转移数据
                os.write(buffer,0,len);
            }
            System.out.println("复制成功!");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • JDK9改进方案

image-20230810161704745.png

public class Way03 {
    //这种方式,吧资源流放在try的外面,但还需要去try/catch,否则只能抛出去
    public static void main(String[] args) throws Exception{
        //1.创建字节输入流与文件接通
        OutputStream os = new FileOutputStream("E:\\TestPhoto\\copy.mp4");
        //2.创建字节输出流
        InputStream is = new FileInputStream("E:\\TestPhoto\\17dfcc00fc81573fd8e77177768e0502.mp4");
        try(os;is) {
            //3.定义字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录读取次数
            while((len = is.read(buffer)) != -1){
                //转移数据
                os.write(buffer,0,len);
            }
            System.out.println("复制成功!");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7.字符流

7.1、字符输入流:一次读取一个字符

image-20230810161713721.png

  • 文件字符输入流:Reader

image-20230810161732792.png

public class Test {
    public static void main(String[] args) throws Exception{
        //1.创建字符输入流与文件接通
        Reader r = new FileReader("Demo/src/data03");
        //2.读取一个字节输出控制台,如果没可读字符返回-1
        /*int code = r.read();
        System.out.println((char)code);*/
        //3.使用循环读取所有字节
        int code;
        while ((code = r.read()) != -1) {
            System.out.println((char)code);
        }
    }
}

7.2、字符输入流:一次读取一个字符数组

  • FileReader
public class Test02 {
    public static void main(String[] args) throws Exception{
        //1.创建字符输入流与文件接通
        Reader r = new FileReader("Demo/src/data03");

        //2.用循环,每次读取一个字符数组的数据
        char[] buffer = new char[1024]; //是1024K字节,而不是1024KB
        int len;//记录每次读取的数量,以防多读(读多少,输出多少)
        while((len = r.read(buffer)) != -1){
            System.out.println(new String(buffer,0,len));
        }
    }
}

7.3、字符输出流

  • 文件字符流输出流:FileWriter

image-20230810161742577.png

  • 写数据出去的API

image-20230810161748913.png

  • 流的关闭和刷新

image-20230810161756322.png

public class Test {
    public static void main(String[] args) throws Exception{
        //1.创建字符输出流与文件接通
        //Writer w = new FileWriter("Demo/src/out.txt");//覆盖管道
        Writer w = new FileWriter("Demo/src/out.txt",true);//追加管道【不清空之前的数据,继续拼接】
        //a.public void write(int c):写一个字符出去
        w.write(97);
        w.write('b');
        w.write('马');
        w.write("\r\n");//换行
        //b.public void wirte(String c):写一个字符串出去
        w.write("马浩楠");
        w.write("\r\n");//换行
        //c.public void write(char[] buffer):写一个字符数组出去
        w.write("张林燕".toCharArray());
        w.write("\r\n");//换行
        //d.public void write(String c,int pos,int len):写字符串的一部分出去
        w.write("I am tired,but I am poor so I must every effort to earn。暗黑哈哈哈",0,55);
        //e.public void write(char[] buffer,int pos,int len):写字符数组的一部分出去
        w.write("爱你",0,1);

        //w.flush();//刷新数据,还可以继续使用流
        w.close();//关闭流,释放资源,包含了刷新舒徐,但不能再继续使用流
    }
}

results matching ""

    No results matching ""