9---File类+递归+IO流初步

1、File类

1、概念:

​ java.io.File类是文件和目录路径名的抽象表示。作用在于:通过路径字符串表示操作系统中的文件或文件夹

2、构造方法
File(String pathname) 通过【路径名】创建一个File对象,这个File对象可以表示文件也可以表示文件夹
File(String parent, String child) 通过【父路径】和【子路径】创建File对象
File(File parent, String child) 通过【父路径File对象】和【子路径】创建File对象

(Ps:构造File类的过程中,并不会创建新的文件夹和文件)

3、利用File类的方法创建文件夹和文件
1、File类的方法:
boolean createNewFile() 创建新文件, 如果创建成功返回true
boolean mkdir() 创建一个文件夹, 如果创建成功返回true 
boolean mkdirs() 创建多级文件夹, 如果创建成功返回true
2、注意:
WINDOWS中文件名不区分大小写
WINDOWS中路径分隔符可以写反斜杠\\,也可以写正斜杠/
public static void main(String[] args) throws IOException {
    test3();
}

// boolean mkdirs() (推荐使用)创建多级文件夹, 如果创建成功返回true
public static void test3() {
    File file = new File("C:/MyFileTest/666/777/888");
    boolean b = file.mkdirs();
    System.out.println(b);
}

// boolean mkdir() 创建一个文件夹, 如果创建成功返回true
public static void test2() {

    //文件名不区分大小写,所以下面两天语句只执行前面那条ccc
    // File file = new File("C:\\MyFileTest\\ccc");
    // File file = new File("C:\\MyFileTest\\CCC");
    File file = new File("C:/MyFileTest/ddd");
    boolean b = file.mkdir();
    System.out.println(b);
}

// boolean createNewFile() 创建新文件,如果创建成功返回true
public static void test1() throws IOException {
    File file = new File("C:\\MyFileTest\\123.txt");

    boolean b = file.createNewFile();
    System.out.println(b);
}
4、利用File类的方法删除文件夹和文件
1、File类的方法:
boolean delete() 删除文件或文件夹,删除成功返回true
2、注意:
删除就没有了.不会在回收站里面
如果文件加里面有内容,需要先删除文件夹里面的内容,再删除空文件夹
// boolean delete() 如果文件加里面有内容,需要先删除文件夹里面的内容,再删除空文件夹
//否则,会删除失败。
public static void test3() {
    File in = new File("C:\\MyFileTest\\ddd\\aaa");
    System.out.println("删除里面内容: " + in.delete());

    File file = new File("C:\\MyFileTest\\ddd");
    boolean b = file.delete();
    System.out.println("删除文件夹: " + b);
}
5、路径分类
1、绝对路径:
从盘符开始的就是绝对路径
    C:/MyFileTest/abc/aaa
    C:/MyFileTest/abc/bbb
2、相对路径:(找到“相对的”参照路径)
没有从盘符开始的就是相对路径
    参照: C:/MyFileTest/abc/
        aaa     ->  完整路径: C:/MyFileTest/abc/aaa
        bbb     ->  完整路径: C:/MyFileTest/abc/bbb
3、工程路径

​ 即idea相对路径的参照。(idea软件的左上角)

以下代码可以打印出工程路径

public class demo4 {
    public static void main(String[] args) {
        File file = new File("aaa");
        System.out.println(file.getAbsoluteFile());
    }
}
6、File的获取功能
1、File类的方法
String getAbsolutePath() 返回绝对路径
String getPath() 返回创建File对象时的路径
String getName() 返回路径的名称(返回文件或者文件夹的名称)
long length() 返回文件的长度(只能获取文件的长度,若是文件夹,长度永远等于0;长度即文件大小,单位是字节)。
public static void main(String[] args) {
    File file = new File("day06\\abc\\123.txt");
    System.out.println(file.getAbsoluteFile());E:\IdeaProjects\Pratice-code\day06\abc\123.txt
    System.out.println(file.getPath());//day06\abc\123.txt
    System.out.println(file.getName());//123.txt
    System.out.println(file.length());//35
}
7、File的判断功能
File类:
    boolean isDirectory() 判断是否是文件夹,如果是返回true
    boolean isFile() 判断是否是文件,如果是返回true
    boolean exists() 判断是否存在(文件或者文件夹),如果存在返回true
public static void main(String[] args) {
    // test1();
    // test2();
    test3();
}

// boolean exists() 判断是否存在,如果存在返回true
public static void test3() {
    // File file = new File("C:\\MyFileTest\\123.txt");
    // File file = new File("C:\\MyFileTest\\aaa");
    File file = new File("C:\\MyFileTest\\xxx");

    System.out.println(file.exists());
}

// boolean isFile() 判断是否是文件,如果是返回true
public static void test2() {
    // File file = new File("C:\\MyFileTest\\123.txt");
    File file = new File("C:\\MyFileTest\\aaa");

    System.out.println(file.isFile());
}

// boolean isDirectory() 判断是否是文件夹,如果是返回true
public static void test1() {
    // File file = new File("C:\\MyFileTest\\aaa");
    File file = new File("C:\\MyFileTest\\123.txt");

    System.out.println(file.isDirectory());
}
8、File的目录遍历功能
1、目录遍历:

目录的遍历就是显示文件夹中的内容(就是双击文件夹)

2、File类中的方法:
String[] list() 列出文件夹里面的所有内容,返回文件名数组
File[] listFiles() (常用) 列出文件夹里面的所有内容,返回File对象数组
3、注意:

​ 文件不能调用list功能(会返回null值)

// 文件不能调用list功能
public static void test3() {
    File file = new File("C:\\MyFileTest\\123.txt");
    File[] files = file.listFiles();
    System.out.println(files); // 返回null
}


    // File[] listFiles() (常用)列出文件夹里面的所有内容,返回File对象数组
public static void test2() {
    File file = new File("C:\\MyFileTest\\aaa");

    // 列出文件夹里面的所有内容,返回File对象数组
    File[] files = file.listFiles();

    for (File f : files) {
        System.out.println(f);
    }
}

// String[] list() 列出文件夹里面的所有内容,返回文件名数组
public static void test1() {
    File file = new File("C:\\MyFileTest\\aaa");

    // 列出文件夹里面的所有内容,返回文件名数组
    String[] list = file.list();
    // 遍历数组
    for (String name : list) {
        System.out.println(name);
    }
}

2、递归

1、概念:

​ 方法自己调用自己

2、应用递归时的注意事项
1.递归要有出口(要有停止递归的条件)
2.递归次数不能够太多(在有停下来的条件的同时,要保证参数少到不回发生栈溢出错误:StackOverError)
public static void main(String[] args) {
    int sum = getSum(5);
    System.out.println(sum);
}
/*
    规律:1到n的和 = n + 1到n-1的和
    出口:当n=1时,返回1

    getSum: 参数写几,就是计算1到几的和
 */
public static int getSum(int n) {
    // 【出口】:当n=1时,返回1   **********************************重要!!!
    if (n == 1) {
        return 1;
    }

    // 规律:1到n的和 = n + 1到n-1的和
    return n + getSum(n-1);
}

// 使用for循环求1-5的和: 1 + 2 + 3 + 4 + 5.txt
public static void test01() {
    int sum = 0;
    for (int i = 1; i <= 5; i++) {
        sum += i;
    }
    System.out.println("sum = " + sum);
}
3、递归和File类综合案例
/*
目标:列出文件夹中的所有java文件

讲解:
    步骤:
        1.定义一个File对象,表示要列出的文件夹

        2.定义一个方法显示dir文件夹里面的java文件:
            listJava(File dir)
                3.列出dir文件夹的所有内容
                4.遍历每个File对象
                5.txt.如果是文件,并且是.java结尾的文件就打印
                6.如果是文件夹,调用listJava(文件夹)

小结:
    以后要操作文件夹,并且文件夹里面还有文件夹,就考虑使用【递归】****************重要!

 */
public class Demo10 {
    public static void main(String[] args) {
        // 1.定义一个File对象,表示要列出的文件夹
        File file = new File("E:\1a黑马java\黑马java\基础班\源程序\Day02");
        listJava(file);
    }

    // 2.定义一个方法显示dir文件夹里面的java文件:
    public static void listJava(File dir) {
        // 3.列出dir文件夹的所有内容
        File[] files = dir.listFiles();
        // 4.遍历每个File对象
        for (File file : files) {
            if (file.isFile()) {
                // 5.txt.如果是文件,并且是.java结尾的文件就打印
                if (file.getName().endsWith(".java")) {
                    System.out.println(file);
                }
            } else {
                // 6.如果是文件夹,调用listJava(文件夹)------>【递归】
                listJava(file);
            }
        }
    }
}

3、I/O流

1、IO流概念:

​ 【对比】:File的功能,操作文件或文件夹如新建,删除,获取信息,(相当于我们图形界面对文件进行鼠标右键操作)

把数据在内存和外部设备之间的流动叫做IO流。已内存为基准,Input/Output 输入/输出流,即流向内存是输入流,流出内存的输出流

2、IO流的作用

​ 通过IO流我们可以读取文件里面的数据,还可以往文件里面写数据。

​ 而对文件的操作很重要。因为之前保存数据使用集合或数组, 集合或数组保存在内存中的.内存一旦断电,就没有了.(内存是临时性存储)。如果想将数据永久存储.需要将数据保存在文件中.

3、IO流的分类
(1)按照数据流向,

​ 分为输入流(数据从设备流向内存)和输出流(数据从内存流向设备)

(2)按操作的类型,

​ 分为字节流:(操作的单位是字节)和 字符流:(操作的单位是字符,方便我们操作字符)

4、根据分类,有四个IO顶级父类
IO流的顶级父类:
                    字节流                                 字符流
    输入流         字节输入流InputStream                字符输入流Reader
    输出流         字节输出流OutputStream               字符输出流Writer

​ PS:特点:这四个类都是抽象类,使用的时候用的是其子类

5、FileOutputStream类:字节输出流
(1)概念:

​ 其父类是OutputStream,中文名为字节输出流

(2)构造方法:

​ 创建流的时候,如果没有对应的文件,则会创建新文件;

​ 有对应的文件,则要看具体方法,判断其是否会覆盖原来的文件进行重新写入(非追加写)和追加写。

FileOutputStream(String name) 创建一个文件字节输出流,流中的数据会流入指定的文件中
FileOutputStream(File file) 创建一个文件字节输出流,流中的数据会流入指定的文件中
(3)IO流的使用步骤:

​ 1.创建IO流
​ 2.读写数据
​ 3.关闭流

(4)普通方法-------往流中写入一个字节数据

​ 非追加写

void write(int b) 将一个字节写入流中
public static void main(String[] args) throws IOException, InterruptedException {
    // FileOutputStream(String name) 创建一个文件字节输出流,流中的数据会流入指定的文件中
    // FileOutputStream fos = new FileOutputStream("day09demo/abc/2.txt");//工程路径...

    // FileOutputStream(File file)
    File file = new File("day09demo/abc/3.txt");//工程路径...
    FileOutputStream fos2 = new FileOutputStream(file);

    // void write(int b) 将一个字节写入流中
    // 我们要写字节byte,参数是int,不怕.
    fos2.write(97);

    // IO流使用完需要关闭
    fos2.close();
    //(字节输出流相当于往文件中“伸出”了一根管子,一直占用着这个文件,
    // 必须关闭才能使该文件“独立”而不被占用,不然会导致“别人”无法对该文件进行操作)


    // 模拟程序一直被占用(程序一直在运行)
    // Thread.sleep(10000);//此时,2.txt文件没办法进行任何操作。

}
(5)普通方法-----往流中写入一个字节数组数据

​ 非追加写

void write(byte[] b) 将字节数组中的数据写入流中
void write(byte[] b, int off, int len) 将字节数组中的部分数据写入流中
		// int off: 从输入哪个索引开始写
        // int len: 写多少个数据
public static void main(String[] args) throws IOException {
    // 1.创建文件字节输出流
    FileOutputStream fos = new FileOutputStream("day09demo/abc/4.txt");

    // 2.写数据
    // void write(byte[] b) 将字节数组中的数据写入流中
    byte[] buf = new byte[] {65, 66, 67, 68, 69};
    // fos.write(buf);
    // void write(byte[] b, int off, int len) 将字节数组中的部分数据写入流中
    // int off: 从输入哪个索引开始写
    // int len: 写多少个数据
    // fos.write(buf, 2, 3);

    // 将字符串转成字节数组-----> 字符串.getBytes();
    byte[] bytes = "你好".getBytes();
    fos.write(bytes);

    // 3.关闭流
    fos.close();
}
(6)普通方法-------往流中追加写一个字节数据

​ 前述的方法在写数据时是会删除以前的数据,进行重新写入。

FileOutputStream(File file, boolean append)
FileOutputStream(String name, boolean append)
当append设置为true时,就不会删掉以前的,在之前的基础上追加写入数据
public static void main(String[] args) throws IOException {
    // FileOutputStream(String name, boolean append)
    FileOutputStream fos = new FileOutputStream("day09demo/abc/4.txt", true);

    fos.write("\r\n".getBytes());
    fos.write(66);
    fos.write(65);

    fos.close();
}
6、FileInputStream类:字节输入流
(1)概念:

​ 其父类是InputStream,中文名为字节输入流

(2)构造方法
FileInputStream(String name) 创建文件字节输入流,读取指定文件中的内容
FileInputStream(File file) 创建文件字节输入流,读取指定文件中的内容
(3)普通方法-------往流中读入一个字节数据
int read() 读取一个字节,返回读取到的字节数据,返回int类型数据

如何循环读取一个字节

int b;
while ((b = fis.read()) != -1) {
    System.out.print((char) b);
}
public static void main(String[] args) throws IOException {
    // 1.创建文件字节输入流
    // FileInputStream(String name) 创建文件字节输入流,读取指定文件中的内容
    // FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");

    // 2.读取数据:hello
    // int read() 读取【下一个】字节数据
    /*int b = fis.read();
    System.out.println((char) b); // h
    b = fis.read();
    System.out.println((char) b); // e
    b = fis.read();
    System.out.println((char) b); // l
    b = fis.read();
    System.out.println((char) b); // l
    b = fis.read();
    System.out.println((char) b); // o
    b = fis.read();
    System.out.println(b); // -1  下一个字节为空时,返回值为-1 */

    // 以上代码是重复代码,我们改用while循环,循环的终止条件是-1
    FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
    // 定义一个变量,保存读取到的数据
    int b;
    // 1.fis.read() 读取一个字节
    // 2.b = fis.read() 将读取的数据保存到b中
    // 3.b != -1 判断b是否为-1,如果不是-1说明读取到数据
    while ((b = fis.read()) != -1) {
        // 读取到了数据
        System.out.print((char) b);
    }

    // 3.关闭流
    fis.close();
}
(4)普通方法-------往流中读入一个字节数组的数据
int read(byte[] b) 读取多个数据,多个数据放到参数的byte数组中,返回读取到的个数

如何循环读取一个字节的数组数据

int len;
byte[] buf = new byte[1024 * 4]; // 通常写1024的整数倍 1024个字节是1kb
while ((len = fis.read(buf)) != -1) {
    System.out.print(new String(buf, 0, len));
}

一次读取一个字节的数组好处

​ IO操作文件时实际上是外存的访问,外存数据的读取,速度是比较慢的。一次读取一个字节数组,相比于一次读取一个字节,总量上减少了读取次数,效率提高了。

public static void main(String[] args) throws IOException {
    // int read(byte[] b) 读取多个数据,多个数据放到参数的byte数组中,返回读取到的个数
    //字符串的构造方法之一:String str = new String(buf);
    /*
    FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
    byte[] buf = new byte[3];
    int len = fis.read(buf);
    System.out.println("长度: " + len); // 3
    System.out.println("内容: " + new String(buf)); // hel

    len = fis.read(buf);
    System.out.println("长度: " + len); // 3
    System.out.println("内容: " + new String(buf)); // low

    len = fis.read(buf);
    System.out.println("长度: " + len); // 3
    System.out.println("内容: " + new String(buf)); // orl

    len = fis.read(buf);
    System.out.println("长度: " + len); // 1
    //(只读取了d,所以数据只覆盖了第一个,后两个没有被覆盖,仍然是前面的rl)
    System.out.println("内容: " + new String(buf)); // drl

    len = fis.read(buf);
    //当下一个将要读取的地方是没有内容可读的时候,实际上是访问到了“文件结束标记”。
    System.out.println("长度: " + len); // -1 没有读取到内容返回-1
    */

    // 我们发现以上是重复代码,故可使用while来解决
    FileInputStream fis = new FileInputStream("day09demo/abc/4.txt");
    // 定义变量,保存读取到的数量
    int len;
    // 定义数组,保存读取到的数据
    byte[] buf = new byte[1024 * 4]; // 【通常写1024的整数倍 1024个字节是1kb】
    // 1.fis.read(buf) 使用字节读取数据,读取到的数据放到参数的数组中
    // 2.len = fis.read(buf) 将读取到的个数保存到len变量中
    // 3.len != -1 判断读取到的个数是否为-1,如果不是-1说明读取到了内容
    while ((len = fis.read(buf)) != -1) {
        // new String(buf, 0, len) 将数组中的【部分数据】转成字符串
        // 第一个参数,数组的哪个位置开始转
        // 第二个参数,转多少个数据
        System.out.print(new String(buf, 0, len));
    }

    fis.close();
}

知识回顾:字符串和字符数组之间的转换关系

/*
1.String转byte[]使用哪个方法?
    byte[] bytes = "hello".getBytes();

2.byte[]转String使用哪个方法?
    String str = new String(buf);
    String str = new String(buf, 0, len) 将数组中的【部分数据】转成字符串
        // 第一个参数,指定字节数组
        // 第二个参数,数组的哪个位置开始转
        // 第三个参数,转多少个数据
*/
public static void main(String[] args) {
    // byte[] 转成 String
    byte[] buf = new byte[] {97, 98, 99, 100};
    String str = new String(buf);
    String str2 = new String(buf,0,3);
    System.out.println("str = " + str); // str = abcd
    System.out.println("str2 = " + str2);

    // String 转成 byte[]
    byte[] bytes = "hello".getBytes();
    System.out.println(Arrays.toString(bytes));
}

(5)案例:图片复制

/*
目标:使用字节流将 "day09demo/abc/xyz.png" 复制到 "c:/MyFileTest/xyz.png"
    图片是以字节的方式存储在文件中

讲解:
    复制文件的步骤:
        1.创建文件字节输入流
        2.创建文件字节输出流
        3.循环读写文件
        4.关流

小结:
    1.字节流复制文件步骤?
        1.创建文件字节输入流
        2.创建文件字节输出流
        3.循环读写文件
        4.关流
 */
public class Demo19 {
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        // copy01(); // 603
        copy02(); // 2
        long end = System.currentTimeMillis();
        System.out.println("消耗时间: " + (end - start));
    }

    // 循环读写文件(一个字节数组)
    public static void copy02() throws IOException {
        // 1.创建文件字节输入流
        FileInputStream fis = new FileInputStream("day09demo/abc/xyz.png");
        // 2.创建文件字节输出流
        FileOutputStream fos = new FileOutputStream("c:/MyFileTest/xyz2.png");

        // 3.循环读写文件(一个字节数组)
        int len;
        byte[] buf = new byte[1024];
        
        long start = System.currentTimeMillis();
        
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        
        long end = System.currentTimeMillis();
        System.out.println(end - start);

        // 4.关流
        fis.close();
        fos.close();
    }

    // 循环读写文件(一个字节)
    public static void copy01() throws IOException {
        // 1.创建文件字节输入流
        FileInputStream fis = new FileInputStream("day09demo/abc/xyz.png");
        // 2.创建文件字节输出流
        FileOutputStream fos = new FileOutputStream("c:/MyFileTest/xyz.png");

        // 3.循环读写文件(一个字节)
        int b;
        
        long start = System.currentTimeMillis();
        
        while ((b = fis.read()) != -1) {
            fos.write(b);
        }
        
        long end = System.currentTimeMillis();
        System.out.println(end - start);

        // 4.关流
        fis.close();
        fos.close();
    }
}
7、FileReader类:字符输入流
(1)概念:

​ 其父类是Reader,中文名为字符输入流

(2)构造方法
FileReader(String fileName) 创建一个新的 FileReader 读取指定文件中的字符
FileReader(File file) 创建一个新的 FileReader 读取指定文件中的字符
(3)普通方法:

​ 和字节输入流相似

int read() 读一个字符, 返回值是读取到的字符
int read(char[] cbuf) 将字符读入数组,返回读取的字符数量
public static void main(String[] args) throws IOException {
    /*FileReader fr = new FileReader("day09demo/abc/6.txt");
    int ch = fr.read();
    System.out.println((char)ch); // 你
    ch = fr.read();
    System.out.println((char)ch); // 不
    ch = fr.read();
    System.out.println((char)ch); // 要
    ch = fr.read();
    System.out.println((char)ch); // 乱
    ch = fr.read();
    System.out.println((char)ch); // 来
    ch = fr.read();
    System.out.println(ch); // -1*/

    // 循环读取一个字符
    /*FileReader fr = new FileReader("day09demo/abc/6.txt");
    int ch; // 定义变量保存读取到的字符
    while ((ch = fr.read()) != -1) {
        System.out.print((char)ch);
    }*/

    // 循环读取一个字符数组
    FileReader fr = new FileReader("day09demo/abc/6.txt");
    int len; // 定义变量保存读取到的数量
    char[] chs = new char[3];
    while ((len = fr.read(chs)) != -1) {
        System.out.print(new String(chs, 0, len));
    }

    fr.close();
}
8、FileWriter类:字符输出流
(1)概念:

​ 其父类是Writer,中文名为字节输出流

(2)构造方法
FileWriter(String fileName) 创建一个文件字符输出流,往指定的文件写数据
FileWriter(File file) 创建一个文件字符输出流,往指定的文件写数据
(3)普通方法
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组。
void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
特有:
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分。
public static void main(String[] args) throws IOException {
    FileWriter fw = new FileWriter("day06/abc/7.txt");

    // 2.写数据

    // void write(int c) 写一个字符
    fw.write('爱');

    // void write(char[] cbuf) 写入一个字符数组。
    char[] chs = new char[] {'我', '想', '要', '个', '女', '同', '桌'};
    fw.write(chs);

    // void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
    fw.write(chs, 2, 4);

    // void write(String str) 写一个字符串
    fw.write("你做梦");

    String sb = "我很随便";
    // void write(String str, int off, int len) 写一个字符串的一部分。
    fw.write(sb, 2, 2);

    // flush:刷新缓冲区,将缓冲区的数据写入文件
    // flush后还可以接着写数据
    fw.flush();
    fw.write("我再来一次");
    // fw.flush();

    // 3.关闭流
    // close:关闭流的时候也会刷新一下
    // close后不能再写数据
    fw.close();
    //fw.write("我又再来一次");//IOException: Stream closed
}

注意flush和close之间的差别!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值