JavaSE进阶、File、方法递归、IO流

目录

一、File文件操作

1、File类概述

2、File类常用操作

3、File类创建和删除文件

4、遍历文件夹

二、方法递归

1、递归形式

2、递归的算法流程、核心要素

3、猴子吃桃问题

4、非规律化递归:文件搜索功能

5、非规律化递归:啤酒问题

三、字符集

字符串编码与解码

四、IO流

 1、IO流 的概述

 2、IO流的分类

 3、IO流体系

 3.1、字节流的使用

        文件字节输入流:每次读取一个字节

        文件字节输入流:每次读取一个字节数组

        文件字节输入流:一次读完全部字节

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

         文件拷贝

 3.2、资源释放的方式 try-catch-finally

        基本做法

        JDK7、JDK9改进方法

 3.3、字符流的使用

        文件字符输入流:一次读取一个字符

        文件字符输入流:一次读取一个字符数组

        文件字符输出流


一、File文件操作

1、File类概述

 public static void main(String[] args) {
        //1、创建file对象(指定文件路径)
        //多于字符删去
        //两个斜杠表示  第一个斜杠告诉后一个斜杠你只是一个斜杠,你不能做转义
        //   也可以使用正斜杠 /         D:/2ProgramTool/JavaTest/filetest/2(2).jpg
        File f = new File("D:\\2ProgramTool\\JavaTest\\filetest\\2(2).jpg");
        //调用API File.separator作为分隔符,可以实现跨平台操作,在不同平台匹配不同分隔符
        File f1 = new File("D:" + File.separator + "2ProgramTool" + File.separator + "JavaTest" + File.separator + "filetest" + File.separator + "(2).jpg");
        //取文件的字节大小
        long length = f.length();
        System.out.println(length);

        //2、File创建对象,支持绝对路径,也支持相对路径(重点)
        //D:\2ProgramTool\JavaTest\filetest\2(2).jpg 从盘符开始 绝对路径

        //相对路径  一般定位模块中的文件,相对在工程下
        //有些文件不能放在电脑的盘符中,会创建在项目中,因为一旦脱离电脑文件就无法使用
        //而创建在模块中的文件可以跟着项目走,使用相对路径引用
        File f2 = new File("file-io-app/src/data.txt");
        System.out.println(f1.length());

        //3、File创建对象,可以是文件也可以是文件夹,但是文件夹不能拿大小
        File f3 = new File("D:\\2ProgramTool\\JavaTest\\filetest");
        //判断这个路径(文件夹)是否存在
        System.out.println(f3.exists());


    }

2、File类常用操作

public static void main(String[] args) {
        //1、相对路径创建一个文件对象
        File f = new File("file-io-app/src/data.txt");
        //a、获取它的绝对路径
        System.out.println(f.getAbsolutePath());
        //b、获取文件定义时使用的路径
        System.out.println(f.getPath());
        //c、获取文件名称:带后缀
        System.out.println(f.getName());
        //d、获取文件的大小:字节个数
        System.out.println(f.length());
        //e、获取文件的最后修改时间(时间毫秒值)
        System.out.println(f.lastModified());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        System.out.println(sdf.format(f.lastModified()));
        //f、判断是文件还是文件夹
        System.out.println(f.isFile());
        System.out.println(f.isDirectory());
    }

3、File类创建和删除文件

public static void main(String[] args) throws IOException {
        //创建文件对象
        File f = new File("file-io-app/src/data2.txt");
        //a、创建新文件成功返回true
        System.out.println(f.createNewFile()); //(几乎不用)

        //b、mkdir 创建一级目录
        File f1 = new File("D:\\2ProgramTool\\JavaTest\\filetest\\aa");
        System.out.println(f1.mkdir());

        //c、mkdirs 创建多级目录
        File f2 = new File("D:/2ProgramTool/JavaTest/filetest/cc/ss/eee");
        System.out.println(f2.mkdirs());

        //d、删除文件或空文件夹,不能删除非空文件夹
        System.out.println(f.delete());
        File f3 = new File("D:\\2ProgramTool\\JavaTest\\filetest\\aa");
        //即使文件被占用仍然强制删除,不走回收站
        System.out.println(f3.delete());

    }

4、遍历文件夹

public static void main(String[] args) {
        //遍历文件夹中的一级目录
        File f = new File("D:\\2ProgramTool\\JavaTest\\filetest");
        //只能拿一级文件
        String[] list = f.list();
        for (String s : list) {
            System.out.println(s);
        }

        //遍历文件夹中的一级文件对象,到一个文件对象数组中去
        //调用listFiles()的必须是一个文件夹
        //包括文件夹中的隐藏文件都会被遍历出来
        File[] files = f.listFiles();
        for (File file : files) {
            System.out.println(file.getName());
            System.out.println(file);
            //对文件夹遍历删除
            //file.delete();
        }
    }

二、方法递归

1、递归形式

public static void main(String[] args) {
        //test();
        test2();
    }
    public static void test(){
        System.out.println("被执行");
        //直接递归
        //递归死循环:递归方法无限调用自己,无法终止,出现栈内存溢出
        test();
    }

    public static void test2(){
        System.out.println("test2被执行");
        //间接递归
        test3();
    }

    private static void test3() {
        System.out.println("test3被执行");
        test2();
    }

2、递归的算法流程、核心要素

 public static void main(String[] args) {

        System.out.println(factorial(30));

    }

    public static int factorial(int n){
        if (n == 1) {
            return 1;
        }else {
            return factorial(n-1) * n;
        }
    }

3、猴子吃桃问题

public static void main(String[] args) {
        //猴子吃桃问题
        //第一天摘下若干个桃子,当即吃了一半又多吃一个,每天如此,到第十天发现桃子只有一个,问摘了多少桃子
        /**
         * f = n/2 - 1
         * 一:n/2 - 1    f1
         * 二:f1/2 - 1  f2
         * 三:f2/2 - 1  f3
         * 。。。
         * 九:f8/2 - 1  f9
         * 十:f9/2 - 1  1
         * n=10  f10 = 1
         * fx - fx/2 -1 = f(x+1)
         */
        System.out.println(eat(1));
    }

    public static int eat(int n){
        if (n == 10){
            return 1;
        }else {
            return (eat(n+1)+1)*2;
        }
    }

4、非规律化递归:文件搜索功能

public static void main(String[] args) {
        LocalTime d = LocalTime.now();
        //在文件夹中搜索文件
        searchFile(new File("D:\\1Amusement"), "QQ.exe");
        LocalTime d2 = LocalTime.now();
        System.out.println("共用时:" + (d2.getSecond() - d.getSecond()));

    }

    private static void searchFile(File dir, String filename) {
        //1、查看是否是在目录中查找文件
        if (dir != null && dir.isDirectory()) {
            //2、对文件夹进行遍历,将遍历到的文件放进文件数组中
            File[] files = dir.listFiles();
            //3、查看遍历到的文件是否是文件夹,或者查找文件是否在一级目录中
            if (files != null && files.length > 0) {
                //5、遍历文件夹
                for (File file : files) {
                    //6、判断遍历到的是文件还是文件夹
                    if (file.isFile()) {
                        //8、判断此文件是不是要查找的文件
                        if (file.getName().contains(filename)) {
                            System.out.println("文件在:" + file.getAbsolutePath());
                            //启动软件
                            Runtime r = Runtime.getRuntime();
                            try {
                                r.exec(file.getAbsolutePath());
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        //7、是文件夹就继续遍历
                        searchFile(file, filename);
                    }
                }
            }
        } else {
            System.out.println("对不起,请在文件夹中进行搜索");
        }
    }

5、非规律化递归:啤酒问题

 通过将瓶子和盖子分别换算成金额然后相加,将换算的金额再进行递归,直到金额小于2。

public class RecusionDemo3 {
    //啤酒总数
    private static int totalBar;
    //剩余瓶子总数
    private static int lastBottle;
    //剩余盖子总数
    private static int lastLid;

    public static void main(String[] args) {
        buy(10);  //10  6 6
        System.out.println("啤酒总数:" + totalBar);
        System.out.println("剩余瓶子总数:" + lastBottle);
        System.out.println("剩余盖子总数:" + lastLid);
    }
    public static void buy(int money){
        //啤酒净购买量
        int buyNummber = money / 2; //5 3 3
        totalBar += buyNummber; //5 + 3 + 3

        //瓶子和盖子能换的钱
        int changeMoney = 0;

        //购买的盖子数量
        int lidNumber = lastLid + buyNummber;  //5 4  3
        //购买的瓶子数量
        int bottleNumber = lastBottle + buyNummber;  //5 4 3

        //盖子能换多少钱
        if (lidNumber >= 4){
            changeMoney += (lidNumber / 4) * 2; //2 2
        }
            lastLid = lidNumber % 4; // 1 0
        //瓶子
        if (bottleNumber >= 2) {
            changeMoney += (bottleNumber / 2) * 2;  //4 4
        }
        lastBottle = bottleNumber % 2; //1 0


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

    }
}

三、字符集

字符串编码与解码

public static void main(String[] args) throws UnsupportedEncodingException {
        //1、编码:把文字转换成字节(使用指定的编码)
        String name = "abc我爱你中国";
        //获取字符串的编码
       // byte[] bytes = name.getBytes();  //以当前代码默认字符集进行编码(UTF-8)

        //用指定字符集进行编码
        //中文字符占两个字节
        byte[] bytes = name.getBytes("GBK");
        System.out.println(bytes.length);

        //打印数组内容
        //字节为负数就是中文,三个字节为一个字符 -26, -120, -111 表示我
        System.out.println(Arrays.toString(bytes));

        //2、解码:把字节转换成对应的中文形式(编码 和 解码使用的字符集必须一致,否则乱码)
       // String rs = new String(bytes);  //以当前代码默认字符集进行编码(UTF-8)
        //指定字符集解码
        String rs = new String(bytes,"GBK");
        System.out.println(rs);
    }

四、IO流

1、IO流 的概述

 2、IO流的分类

3、IO流体系

 3.1、字节流的使用

理解成管道,读取一个字节相当于获取一滴水

  • 文件字节输入流:每次读取一个字节

一次获取一滴水

public static void main(String[] args) throws IOException {
        //File f = new File("file-io-app/data.txt");
        //System.out.println(f.getAbsolutePath());

        //1、创建一个文件字节输入流管道与源文件接通
        //直接放字符串地址实际仍然是通过内部new一个文件对象
        InputStream is = new FileInputStream("D:\\2ProgramTool\\JavaTest\\file-io-app\\src\\data.txt");
        //读取一个字节返回,读取一滴水
        int b = is.read();
        System.out.println(b);
        //查看字符内容
        System.out.println((char) b);

        //is.read();
        //读取完毕后返回-1
        System.out.println(is.read());

        //可以使用循环读取水滴,但是一次只能读取一个字节,遇到中文三个字节就会乱码,性能很差
        //定义一个变量记录每次读取的字节
        /*int c;
        while ((c = is.read()) != -1){
            System.out.print((char) c);
        }*/

    }
  • 文件字节输入流:每次读取一个字节数组

    一次获取一桶水

public static void main(String[] args) throws Exception {

        InputStream is1 = new FileInputStream("D:\\2ProgramTool\\JavaTest\\file-io-app\\src\\data2.txt");

        //2、一次读取一个字节数组返回,如果字节以及没有可读的返回-1
        //相当于用一个桶来接管道中的水滴
        //定义一个桶,桶可以重复使用
        //byte[] buffer = new byte[1024]; 一次读1024个字节 也就是1KB的数据
        byte[] buffer = new byte[3];

        //先接第一桶      每次读取的字节数
        int read = is1.read(buffer);
        System.out.println(read);

        //对字节数组进行解码
        String rs = new String(buffer);
        System.out.println(rs); //abc

        //接第二桶      每次读取的字节数
        //接第二桶时会倒出第一桶中的水
        int read2 = is1.read(buffer);
        System.out.println(read2);

        //对字节数组进行解码
        String rs2 = new String(buffer);
        //read=[a,b,c]    //read2=[1,2,c],只有两滴水,第三滴水还在桶内,所以输出三个字节
        //多输出了一个字节c是因为上一桶的水没有倒干净
        System.out.println(rs2); //12c
        //读多少水就倒多少水
        String rs3 = new String(buffer,0,read2); //0表示从桶底开始装
        System.out.println(rs3);


        //使用循环每次读取一个字节数组
        int len;//记录每次读取的字节数
        while ((len = is1.read(buffer)) != -1){
            //读多少倒多少
            System.out.println(new String(buffer, 0, len));

        }
    }

这两种方式都无法解决读入中文字符乱码的问题

  • 文件字节输入流:一次读完全部字节

文件相当于池塘,一次定义另一个池塘,直接将文件所有字节装进池塘。

 public static void main(String[] args) throws Exception {
        //1、创建一个文件字节输入流管道与源文件接通
        //创建一个文件对象,获取池塘大小
        File f = new File("file-io-app\\src\\data3.txt");
        InputStream fs = new FileInputStream(f);

        //2、定义一个字节数组与文件大小相同
        //定义一个池塘,大小与文件池塘相同
        //强转原因:由于文件大小随机,防止定义的桶过大,将内存挤爆
        byte[] buffer = new byte[(int) f.length()]; //直接强转为int型
        System.out.print(fs.read(buffer)); //返回读取的字节数

        //3、对数据进行解码
        //读取后的字节就会存放在buffer中
        String s = new String(buffer);
        System.out.println(s);

        //一次读取全部字节 官方API
        byte[] buffer1 = fs.readAllBytes();
        System.out.println(new String(buffer1));
    }

 但是一次读完全部字节也存在问题,如果文件过大,字节数组可能引起内存溢出,所以使用字节输入流不适合读文本内容。字符流可以专门用于读取文本内容。

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

 public static void main(String[] args) throws Exception {
        //创建一个文件字节输出流管道与源文件接通
        OutputStream os = new FileOutputStream("file-io-app\\src\\data4.txt",true);

        //通过管道向文件写入内容
        //1、一次写入一个字符
        os.write(34);
        os.write('a');
        //将字符串转成字节数组,输出换行 windows中\n是换行但其它系统不一定,使用\r\n更保险
        os.write("\r\n".getBytes());
        os.write(99);

        //2、一次写入一个字节数组(桶)
        byte[] buffer = {'b',34,97,78,34};
        os.write(buffer);
        //写入汉字
        byte[] buffer2 = "年初鲜花卡".getBytes();  //以当前字符集默认格式编码
        os.write(buffer2);

        //3、写入字节数组的一部分
        byte[] buffer3 = {'b',34,97,78,34};
        os.write(buffer3,0,3);

        //写完数据要刷新数据,关闭管道同时也可以刷新数据
        //每次写入数据时,管道都会将内容存放在一个自带的内存缓冲区中,然后再从缓冲区向文件流数据
        //os.flush();  刷新相当于将所有数据从缓冲区抖出去,不刷新有可能有的数据写不进去
        //管道使用完后一定要关闭管道,否则影响系统性能,相当于系统后台
        os.close();
    }

 每次向文件中写入数据,管道都会对文件原本内容进行情况,假如文件中原本有数据,再向文件写入数据时,会将原有内容清空

FileOutputStream管道被创建后会先清空文件的数据再向文件中写入数据,因此也叫追加管道,如果不希望每次写入都清空,则:

//追加一个true
OutputStream os = new FileOutputStream("file-io-app\\src\\data4.txt",true);
  •  文件拷贝

public static void main(String[] args) throws Exception {
        //文件复制,无论是文件还是视频都可以

        //创建文件字节输入流与源文件接通
        InputStream is = new FileInputStream("C:\\Users\\misGood\\Desktop\\1.jpg");
        //用一个池塘将源文件一次打包
        byte[] buffer = is.readAllBytes();
        //创建文件字节输出流与源文件接通
        OutputStream os = new FileOutputStream("D:\\2ProgramTool\\JavaTest\\file-io-app\\1.jpg");
        //将池塘内的文件全部倒入源文件
        os.write(buffer);
        //关闭管道资源
        os.close();
    }

 3.2、资源释放的方式 try-catch-finally

基本做法

 如果IO流操作中出现异常,则可能导致管道资源无法关闭,无法执行到关闭语句。

public static void main(String[] args) {
        byte[] buffer = new byte[0];
        OutputStream os = null;
        InputStream is = null;
        try {
            //创建文件字节输入流与源文件接通
            is = new FileInputStream("file-io-app/src/data3.txt");
            //用一个池塘将源文件一次打包
            buffer = is.readAllBytes();
            //创建文件字节输出流与源文件接通
            os = new FileOutputStream("file-io-app/src/data4.txt", true);
            //将池塘内的文件全部倒入源文件
            os.write(buffer);

            //操作中间抛异常,无法执行到关闭语句
            int a = 10 / 0;

            //即使代码中有return干掉方法,也要等finally执行完毕
            return;


        } catch (IOException e) {
            e.printStackTrace();
          //开发中不建议在finally中添加return,因为他会使程序直接返回return的内容
        } finally {
            //关闭管道资源
            try {
                if (os != null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //使用finally即使中间抛异常仍然可以关闭管道资源
            //必须等finally执行完才会结束语句
            System.out.println("Finally被执行");
        }
    }

 JDK7、JDK9改进方法

public static void main(String[] args) {
        //JDK7改进方法
        try(InputStream is = new FileInputStream("file-io-app/src/data3.txt"))
         {
            //创建文件字节输入流与源文件接通
            //用一个池塘将源文件一次打包
            byte[] buffer = is.readAllBytes();
            //操作中间抛异常,无法执行到关闭语句
            int a = 10 / 0;
            //即使代码中有return干掉方法,也要等finally执行完毕
            return;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 3.3、字符流的使用

  • 文件字符输入流:一次读取一个字符

 public static void main(String[] args) throws Exception {
        //目标:每次读取一个字符
        //1、创建一个字符输入流管道与源文件接通
        Reader fr = new java.io.FileReader("file-io-app/src/data.txt");

        //2、读取一个字符并返回编号,没有返回-1
        /*int code = fr.read();
        System.out.print((char)code);
        int code2 = fr.read();
        System.out.print((char)code2);
        */
        //3、使用循环读取字符
        int code;
        while ((code = fr.read()) != -1){
            //文本内容自带换行,读取字符时不需要换行
            System.out.print((char) code);
        }
    }

字节流读取数据返回的结果是 读取到的字节数; 字符流读取数据返回的结果是 字符对应的编码ASCILL码。

  • 文件字符输入流:一次读取一个字符数组

public static void main(String[] args) throws Exception {
        //目标:每次读取一个字符数组
        //1、创建一个字符输入流管道与源文件接通
        Reader fr = new java.io.FileReader("file-io-app/src/data.txt");

        //2、每次读取一个字符数组的数据
        //char[] buffer = new char[1024]; //每次读取1K个字符
        char[] buffer = new char[30]; //每次读取10个字符

        //3、使用循环读取字符
        int len;
        //len 表示一次读取的字符个数
        while ((len = fr.read(buffer)) != -1){
            //对读取的内容进行解码
            String s = new String(buffer,0,len);

            //查看一次读取的字符个数
            System.out.print(len);
            //30303030303030303030303025
            
            //文本内容自带换行,读取字符时不需要换行
            System.out.print(s);
        }
    }
  • 文件字符输出流

public static void main(String[] args) throws Exception {
        //1、创建一个字符输出流管道与源文件接通
        //不需要创建文件,自动生成,覆盖管道,每次启动会清空之前的数据
        Writer fw = new FileWriter("file-io-app/src/data5.txt",true);

        //2、一次写一个字符出去  从内存写入磁盘
        fw.write(80);
        fw.write('w');
        fw.write("\r\n");

        //3、一次写一个字符串出去
        fw.write("wuc");
        fw.write("大家比较阿布");
        fw.write("\r\n");

        //4、一次写一个字符数组出去
        char[] c = "asnjca五年快餐".toCharArray();
        fw.write(c);
        fw.write("\r\n");

        //5、一次写一个字符数组的一部分
        fw.write(c,6,3);

        //6、一次写一个字符串的一部分
        fw.write("caca馅儿饼",0,5);

        //fw.flush();
        fw.close();

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值