Java学习-File、方法递归、IO流

目录

1 File类

1.1 File类概述

1.2 常用API

2 方法递归

2.1 概述

2.2 案例

2.2.1 计算1-n的阶乘

2.2.2 计算1-n的和

2.2.3 猴子吃桃问题

2.3 非规律化递归

2.3.1 文件搜索

2.3.2 啤酒问题

3 字符集

3.1 概述

3.2 编码、解码

4 IO流

4.1 概述

4.2 字节流

4.2.1 文件字节输入流: FileInputStream

4.2.2 文件字节输出流: FileOutputStream

4.2.3 文件拷贝

4.2.4 资源释放

4.3 字符流

4.3.1 文件字符输入流: FileReader

4.3.2 文件字符输出流: FileWriter


1 File类

1.1 File类概述

  • File类在包java.io.File下、代表操作系统的文件对象(文件、文件夹)。
  • File类提供了诸如: 定位文件,获取文件本身的信息、删除文件、创建文件(文件夹)等功能。
     

File类创建对象

public File(String pathname)                   根据文件路径创建文件对象
public File(String parent, String child)      从父路径名字符串和子路径名字符串创建文件对象
public File(Fileparent, String child) 根据父路径对应文件对象和子路径名字符串创建文件对象

  •  File对象可以定位文件和文件夹
  • File封装的对象仅仅是一个路径名, 这个路径可以是存在的,也可以是不存在的。
        //1.绝对路径
        File file = new File("D:\\图片\\壁纸\\1.jpg");
        long size = file.length();//获得文件的大小,单位:字节
        System.out.println(size);

        //2.相对路径,相对到此工程下,从工程下的目录开始写
        File file1 = new File("file-io/src/data.txt");
        System.out.println(file1.length());//6

        //3.不仅可以指定具体文件创建对象,还可以指定文件夹
        File file2 = new File("D:\\图片\\壁纸");
        //exists判断文件夹是否存在
        System.out.println(file2.exists());
        File file3 = new File("D:\\图片\\壁纸2");
        System.out.println(file3.exists());

1.2 常用API

public boolean isDirectory( )                        测试此抽象路径名表示的F ile是否为文件夹
public boolean isFile( )                                测试此抽象路径名表示的File是否为文件
public boolean exists()                                测试此抽象路径名表示的File是否存在
public String getAbsolutePath()                  返回此抽象路径名的绝对路径名字符串
public String getPath()                                将此抽象路径名转换为路径名字符串
public String getName()                              返回由此抽象路径名表示的文件或文件夹的名称
public long lastModified()                            返回文件最后修改的时间毫秒值

        //1.绝对路径
        File file = new File("D:\\图片\\壁纸\\1.jpg");
        //a.获取它的绝对路径
        System.out.println(file.getAbsolutePath());
        //b.获取文件定义时候的路径
        System.out.println(file.getPath());
        //c.获取文件的名称,带后缀
        System.out.println(file.getName());
        //d.获取文件的大小
        System.out.println(file.length());
        //e.获取文件最后修改时间
        long time = file.lastModified();
        System.out.println("最后修改时间:"+new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time));
        //f.判断是文件还是文件夹
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());

        System.out.println("============================");

        //2.相对路径
        File file1 = new File("file-io/src/data.txt");
        //a.获取它的绝对路径
        System.out.println(file1.getAbsolutePath());
        //b.获取文件定义时候的路径
        System.out.println(file1.getPath());
        //c.获取文件的名称,带后缀
        System.out.println(file1.getName());
        //d.获取文件的大小
        System.out.println(file1.length());
        //e.获取文件最后修改时间
        long time1 = file1.lastModified();
        System.out.println("最后修改时间:"+new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time1));
        //f.判断是文件还是文件夹
        System.out.println(file1.isFile());
        System.out.println(file1.isDirectory());

 public boolean createNewFile( )创建一一个新的空的文件
public boolean mkdir()只能创建一级文件夹
public boolean mkdirs()可以创建多级文件夹
public boolean delete()删除由此抽象路径名表示的文件或空文件夹

  • delete方法 直接删除不走回收站;如果删除的是-个文件,且文件没有被占用则直接删除
  • delete方法默认只能删除空文件夹。
        //创建文件,基本上用不到
        File file = new File("file-io/src/data.txt");
        System.out.println(file.createNewFile());//false

        File file1 = new File("file-io/src/data2.txt");
        System.out.println(file1.createNewFile());//true

        //创建文件夹
        File file2 = new File("D:\\图片\\壁纸\\aaa");
        //只能创建一级目录
        System.out.println(file2.mkdir());
        File file3 = new File("D:\\图片\\壁纸\\bbb\\ccc\\ddd");
        //创建多级目录
        System.out.println(file3.mkdirs());

        //删除文件或空文件夹
        File file4 = new File("D:\\图片\\壁纸\\aaa");
        System.out.println(file4.delete());
        File file5 = new File("D:\\图片\\壁纸\\bbb");
        System.out.println(file5.delete());//false

File类的遍历功能
public String[] list()      获取当前目录下所有的"一级文件名称"到一一个字符串数组中去返回。
public File[] listFiles()(常用)     获取当前目录下所有的"一-级文件对象"到一个文件对象数组中去返回(重点)


listFiles方法注意事项:

  • 当调用者不存在时,返回null
  • 当调用者是一一个文件时,返回null
  • 当调用者是一个空文件夹时,返回一个长度为0的数组
  • 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回.
  • 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容

        File file = new File("D:\\图片\\壁纸");
        File[] files = file.listFiles();
        for (File f : files) {
            System.out.println(f.getAbsolutePath());
        }

2 方法递归

2.1 概述

什么是方法递归?

  • 方法直接调用自己或者间接调用自己的形式称为方法递归( recursion)。
  • 递归做为一种算法在程序设计语言中广泛应用。

递归的形式

  • 直接递归:方法自己调用自己。
  • 间接递归: 方法调用其他方法,其他方法又回调方法自己。

方法递归存在的问题?

  • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象。
    public static void main(String[] args) {
        test();
    }

    private static void test() {
        System.out.println("test方法执行了。。。");
        test();
    }

2.2 案例

2.2.1 计算1-n的阶乘

需求:计算1-n的阶乘的结果,使用递归思想解决,我们先从数学思维上理解递归的流程和核心点。
分析
①假如我们认为存在-一个公式是f(n)= 1*2*3*4*5*6*7*...(n-1)*n; 
②那么公式等价形式就是: f(n)= f(n-1)*n
③如果求的是1-5的阶乘的结果,我们手工应该应该如何应用上述公式计算。
④f(5)= f(4)*5
   f(4)= f(3)*4
   f(3)= f(2) * 3
   f(2)= f(1)* 2
   f(1)= 1

    public static void main(String[] args) {
        System.out.println(factorial(5));
    }

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

    }

递归解决问题的思路:

  • 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。

递归算法三要素大体可以总结为:

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

2.2.2 计算1-n的和

    public static void main(String[] args) {
        System.out.println(sum(5));
    }

    private static int sum(int n) {
        if (n == 1){
            return 1;
        }else {
            return n + sum(n - 1);
        }
    }

2.2.3 猴子吃桃问题

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

package com.zwit.d2_recursion;
/*
x代表天数,f(x)代表桃子个数
f(x)/2-1 = f(x+1)
f(x) - 2 = 2f(x+1)
f(x) = 2f(x+1) + 2
 */
public class Test04 {
    public static void main(String[] args) {
        System.out.println(sum(1));
    }

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


2.3 非规律化递归

2.3.1 文件搜索

需求:文件搜索、从C:盘中,搜索出某个文件名称并输出绝对路径。
分析:
①先定位出的应该是一级文件对象
②遍历全部一级文件对象,判断是否是文件
③如果是文件,判断是否是自己想要的
④如果是文件夹,需要继续递归进去重复上述过程
 

package com.zwit.d2_recursion;

import java.io.File;

public class Test05 {
    public static void main(String[] args) {
        searchFile(new File("D:/"),"蜘蛛侠.jpg");
    }
    public static void searchFile(File dir,String name){
        //1.判断是否为目录
        if (dir != null && dir.isDirectory()){
            //2.将目录中的目录或文件遍历出来
            File[] files = dir.listFiles();
            //3.判断是否存在一级目录对象
            if (files != null && files.length > 0){
                //继续遍历
                for (File file : files) {
                    if (file.isFile()){
                        //如果是文件,判断是不是要找的
                        if (file.getName().contains(name)){
                            System.out.println("找到了:" + file.getAbsolutePath());
                        }
                    }else {
                        searchFile(file,name);
                    }
                }
            }
        }else {
            System.out.println("对不起,没有此目录,滚滚滚!!");
        }
    }
}

2.3.2 啤酒问题

需求:啤酒2元1瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问10元钱可以喝多少瓶酒,剩余多少空瓶和盖子。
答案: 15瓶3盖子1瓶子
 

3 字符集

3.1 概述

字符集基础知识:

  • 计算机底层不可以直接存储字符的。计算机中底层只能存储二进制(0、1)
  • 二进制是可以转换成十进制的
     

ASCII字符集:

  • ASCI(American Standard Code for Information Interchange,美国信息交换标准代码):包括了数字、英文、符号。
  • ASCII使用1个字节存储一 个字符,一个字节是8位,总共可以表示128个字符信息,对于英文,数字来说是够用的。


GBK:

  • window系统默认的码表。兼容ASCII码表,也包含了几万个汉字,并支持繁体汉字以及部分日韩文字。
  • 注意: GBK是中国的码表, - -个中文以两个字节的形式存储。但不包含世界上所有国家的文字。
     

Unicode码表:

  • unicode (又称统-码、万国码、单- 码)是计算机科学领域里的一项业界字符编码标准。
  • 容纳世界上大多数国家的所有常见文字和符号。

由于Unicode会先通过UTF-8,UTF-16, 以及UTF-32的编码成二进制后再存储到计算机,其中最为常见的就是UTF-8。


注意

  • Unicode是万国码,以UTF-8编码后-个中文- 般以三个字节的形式存储。
  • UTF- 8也要兼容ASCII编码表。
  • 技术人员都应该使用UTF-8的字符集编码。
  • 编码前和编码后的字符集需要一致, 否则会出现中文乱码。
     

3.2 编码、解码

String编码
byte[] getBytes()使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数
组中
byte[] getBytes(String charsetName)使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

String解码
String(byte[] bytes)通过使用平台的默认字符集解码指定的字节数组来构造新的
String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来构造新的String

        String name = "abc我爱你王德发";
        //byte[] bytes = name.getBytes();//编码,默认UTF-8
        byte[] bytes = name.getBytes("GBK");//指定编码GBK
        System.out.println(bytes.length);
        System.out.println(Arrays.toString(bytes));

        //解码,默认UTF-8解码
        String rs = new String(bytes);
        System.out.println(rs);
        //也可以指定
        String rs1 = new String(bytes, "GBK");
        System.out.println(rs1);

4 IO流

4.1 概述

  • I表示intput, 是数据从硬盘文件读入到内存的过程,称之输入,负责读。
  • O表示output, 是内存程序的数据从内存到写出到硬盘文件的过程,称之输出,负责写。
     

IO流的分类

  • 按流的方向分:输入流、输出流
  • 按流中的数据最小单位分为:字节流、字符流

4.2 字节流

4.2.1 文件字节输入流: FileInputStream

  • 作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。

public FileInputStream(File file)创建字节输入流管道与源文件对象接通
public FilelnputStream(String pathname)创建字节输入流管道与源文件路径接通
public int read()每次读取一个字节返回,如果字节已经没有可读的返回-1
public int read(byte[] buffer)每次读取一 个字节数组返回, 如果字节已经没有可读的返回-1

每次读取一个字节存在什么问题?

  • 性能较慢
  • 读取中文字符输出无法避免乱码问题。

        //1.创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io/src/data.txt");
        //2.读取一个字节
        int read = is.read();//返回的是ASCII码
        System.out.println(read);
        System.out.println((char)read);
        int read1 = is.read();
        System.out.println((char)read1);
        int read2 = is.read();
        System.out.println((char)read2);
        int read3 = is.read();
        System.out.println(read3);//读取结束返回-1

可能会出现乱码,或者输出本该不属于它的字节

解决方法:指定输出字节数

        //1.创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io/src/data2.txt");
        //2.创建一个字节数组,用来装字节,本次一次最多装三个字节
        byte[] buffer = new byte[3];
        int len = is.read(buffer);//表示一次读几个字节
        System.out.println("本次读字节数:" + len);
        String s = new String(buffer);
        System.out.println(s);

        int len1 = is.read(buffer);//表示一次读几个字节
        System.out.println("本次读字节数:" + len1);
        String s1 = new String(buffer);
        System.out.println(s1);

        int len2 = is.read(buffer);//表示一次读几个字节
        System.out.println("本次读字节数:" + len2);
        String s2 = new String(buffer,0,len2);
        System.out.println(s2);

 改进:使用循环

        //3.改进:使用循环
        byte[] buffer = new byte[3];
        int len;
        while ((len = is.read(buffer)) != -1){
            System.out.print(new String(buffer,0,len));
        }

以上都无法解决中文的乱码情况

解决方法:

  • 一次性读取完全部字节。
  • 可以定义与文件- 样大的字节数组读取,也可以使用官方API.
     
        //1.创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io/src/data3.txt");
        //2.解决中文乱码,直接用官方提供的API
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));

4.2.2 文件字节输出流: FileOutputStream

        //1.创建一个文件字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("file-io/src/out01.txt");//每次会先清空原来的数据
        //2.写数据出去
        os.write('a');
        os.write(98);
        //os.write('中');//一次只能写出一个字节。中文是三个字节
        os.write("\r\n".getBytes());//换行

        //写一个字节数组出去
        byte[] bytes = {'a',98,99,100};
        os.write(bytes);
        os.write("\r\n".getBytes());//换行

        //写中文
        byte[] bytes1 = "我爱你王德发".getBytes();//利用getBytes将字符串编码为Byte序列
        os.write(bytes1);


        //最后要关闭这个流
        os.close();

4.2.3 文件拷贝

需求:

  • 把某个视频复制到其他目录下的“b.avi" 

思路:
①根据数据源创建字节输入流对象
②根据目的地创建字节输出流对象
③读写数据,复制视频
④释放资源
 

package com.zwit.outputstream;

import java.io.*;

//使用字节流完成文件的复制
public class CopyTest {
    public static void main(String[] args) {
        try {
            //1.想要复制的文件
            InputStream is = new FileInputStream("D:\\谷歌下载\\M3U8批量下载器\\output\\瑜伽教练.mp4");
            //2.复制文件的目的目录
            OutputStream os = new FileOutputStream("D:\\谷歌下载\\M3U8批量下载器\\new瑜伽教练.mp4");
            //3.创建一个桶用户装数据,一次装1024
            byte[] buffer = new byte[1024];
            //4.拿到数据
            int len;
            while ((len = is.read(buffer)) != -1){
                //写出数据,也就是复制数据
                os.write(buffer,0,len);
            }
            System.out.println("复制完成了!");

            //5,关闭数据流
            os.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.2.4 资源释放

上个案例中,释放资源前可能出现异常就无法释放资源了

解决方法一:try-catch-finally
finally: 在异常处理时提供finally块来执行所有清除操作,比如说I0流中的释放资源
特点:被finally控制的语句最终一定会执行, 除非JVM退出
异常处理标准格式: try...catch..finally

package com.zwit.resource;

import java.io.*;

public class TryCatchTest01 {
    public static void main(String[] args) {
        InputStream is = null;
        OutputStream os = null;
        try {
            //1.想要复制的文件
            is = new FileInputStream("D:\\谷歌下载\\M3U8批量下载器\\output\\瑜伽教练.mp4");
            //2.复制文件的目的目录
            os = new FileOutputStream("D:\\谷歌下载\\M3U8批量下载器\\new瑜伽教练.mp4");
            //3.创建一个桶用户装数据,一次装1024
            byte[] buffer = new byte[1024];
            //4.拿到数据
            int len;
            while ((len = is.read(buffer)) != -1){
                //写出数据,也就是复制数据
                os.write(buffer,0,len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5,关闭数据流
            try {
                if (os!=null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is!=null)is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

解决方法二:try-catch-resource

4.3 字符流

4.3.1 文件字符输入流: FileReader

中文乱码解决使用字符流就行了。。

1、字节流读取中文输出可能会存在什么问题?

  • 会乱码。或者内存溢出。

2、读取中文输出,哪个流更合适,为什么?

  • 字符流更合适,最小单位是按照单个字符读取的。

文件字符输入流: Reader

  • 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。

public FileReader(File file)创建字符输入流管道与源文件对象接通
public FileReader(String pathname)创建字符输入流管道与源文件路径接通
public int read()每次读取一个字符返回,如果字符已经没有可读的返回-1
public int read(harQ buffer)每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1

    public static void main(String[] args) throws IOException {
        Reader r = new FileReader("file-io\\src\\data3.txt");
        //一次读出一个字符
        /*int code = r.read();
        System.out.println((char) code);

        //改进
        while ((code=r.read()) != -1){
            System.out.print((char)code);
        }*/

        //这样效率还是很低
        //用字符数组读取
        char[] buffer = new char[1024];
        int len;
        while ((len=r.read(buffer)) != -1){
            String s = new String(buffer, 0, len);
            System.out.println(s);
        }
    }

4.3.2 文件字符输出流: FileWriter

  • 作用:以内存为基准,把内存中的数据以字符的形式写出到磁盘文件中去的流。
        //Writer w = new FileWriter("file-io\\src\\out02.txt");
        //追加数据
        Writer w = new FileWriter("file-io\\src\\out02.txt",true);
        w.write(99);
        w.write("\r\n");//换行
        w.write("嗨嗨嗨");
        w.write("\r\n");//换行
        char[] chars = "我爱你王德发".toCharArray();
        w.write(chars);
        w.write("\r\n");//换行

        w.close();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值