JavaSE进阶——Day10 File类、IO流、字节流

该篇主要讲解Java中File类、IO流、字节流

File类

什么是File类?

  • java.io.File类是java语言提供了用来描述 磁盘文件 和磁盘目录 的

创建

1
2
3
4
5
6
7
public File(String path)

//文件对象
File file = new File("F:\JavaSE进阶_day10\01_课件\小记.txt");

//目录对象
File dir = new File("F:\JavaSE进阶_day10\01_课件");
1
2
3
4
5
6
7
public File(String parent , String child)//基于父路径 和子路径 合并 后,生成File对象

//文件对象
File file = new File("F:\JavaSE进阶_day10\01_课件","小记.txt");

//目录对象
File dir = new File("F:\" , "JavaSE进阶_day10\01_课件");

MacOS不太一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package file;

import java.io.File;
import java.io.IOException;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/28 13:03
* @Project JavaCode_SE_Advance
* @Theme File类
*/
public class demo1 {
public static void main(String[] args) throws IOException {

//创建File对象并创建文件夹
new File("./day10/src/test/").mkdir(); //需要mkdir()方法

//指定文件夹下创建文件
File file = new File("./day10/src/test/", "test.md");
file.createNewFile(); //需要createNewFile()方法

System.out.println(file);

}
}

mkdir和mkdirs就是一个可以创建父类文件,一个只能创建一个子文件

删除

1
2
3
文件对象.delete(); //返回值是布尔值

注意:只能删除空目录

常用方法

image-20240428133456984

练习

统计文件个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package file;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/28 15:48
* @Project JavaCode_SE_Advance
* @Theme 统计文件个数
*/
public class Demo2 {
public static void main(String[] args) {
String path = "day10/src/resources/";
mothed(path);
}

private static void mothed(String path) {
// 利用HashMap统计个数
Map<String, Integer> fileMap = new HashMap<>();
File file = new File(path);
// 判断文件夹存在
if (file.exists()) {

// 1.创建file对应数组
File[] files = file.listFiles();

// 2.遍历文件数组并对文件格式进行提取
for (File f : files) {
String name = f.getName();//获取文件名
String s = name.split("\\.")[1]; //获取文件类型名, 对于多个.的文件名不能使用
//String s = name.lastIndexOf(".")// 获取.所在的索引

// 3.统计个数
if (fileMap.get(s) == null){
fileMap.put(s, 1);
}else{
int n = fileMap.get(s);
n++;
fileMap.put(s, n);

}
}
} else {
throw new RuntimeException("输入文件路径不存在");
}
System.out.println(fileMap);
}
}

io流

IO流解决程序中的什么问题?

  • 把程序中存储在内存中的数据,写入到文件中(持久存储)
  • 把磁盘文件中存储的数据,读取到内存中

IO流:

  • I流: 把磁盘文件中存储的数据,读取到内存中(读数据)
  • O流:把内存中的数据,写入到磁盘文件(写数据)

InputStream:输入流

  • 字节输入流
  • 字符输入流

OutputStream:输出流

  • 字节输出流
  • 字符输出流

字节流:万能流(所有类型的文件都可以读写)

字符流:通常用于针对纯文本文件进行读写操作

  • 纯文本文件: 使用计算机中的记事本软件打开并看得懂的文件

File类,只能针对文件本身进行创建、删除(无法对文件中存储的内容进行操作的)

使用IO流,对文件中存储的内容进行操作(读、写)

IO流中的基础流:

  • 字节流
  • 字符流

IO流的作用:对磁盘上的文件进行读、写操作

  • 读:输入流
  • 写:输出流(把内存中的数据写入到磁盘文件中)

字节流输出流

字节输出流入门

  • FileOutputStream类 :

    • OutputStream有很多子类,我们从最简单的一个子类开始。
    • java.io.FileOutputStream类是文件输出流,用于将数据写出到文件
  • 构造方法 :

    • public FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
    • public FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class FileOutputStreamConstructor throws IOException {
    public static void main(String[] args) {
    // 使用File对象创建流对象
    File file = new File("a.txt");
    FileOutputStream fos = new FileOutputStream(file);

    // 使用文件名称创建流对象
    FileOutputStream fos = new FileOutputStream("b.txt");
    }
    }
  • 字节输出流写数据快速入门

    • 创建字节输出流对象。
    • 写数据
    • 释放资源
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.itheima.outputstream_demo;

    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /*
    字节输出流写数据快速入门 :
    1 创建字节输出流对象。
    2 写数据
    3 释放资源
    */
    public class OutputStreamDemo1 {
    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    // 如果指定的文件不存在 , 会自动创建文件
    // 如果文件存在 , 会把文件中的内容清空
    FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");

    // 写数据
    // 写到文件中就是以字节形式存在的
    // 只是文件帮我们把字节翻译成了对应的字符 , 方便查看
    fos.write(97);
    fos.write(98);
    fos.write(99);

    // 释放资源
    // while(true){}
    // 断开流与文件中间的关系
    fos.close();
    }
    }

字节输出流写数据的方法

  • 字节流写数据的方法

    • 1 void write(int b) 一次写一个字节数据
    • 2 void write(byte[] b) 一次写一个字节数组数据
    • 3 void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package com.itheima.outputstream_demo;

    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /*
    字节流写数据的3种方式
    1 void write​(int b) 一次写一个字节数据
    2 void write​(byte[] b) 一次写一个字节数组数据
    3 void write​(byte[] b, int off, int len) 一次写一个字节数组的部分数据
    */
    public class OutputStreamDemo2 {
    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");

    // 写数据
    // 1 void write​(int b) 一次写一个字节数据
    fos.write(97);
    fos.write(98);
    fos.write(99);

    // 2 void write​(byte[] b) 一次写一个字节数组数据
    byte[] bys = {65, 66, 67, 68, 69};
    fos.write(bys);

    // 3 void write​(byte[] b, int off, int len) 一次写一个字节数组的部分数据
    fos.write(bys, 0, 3);

    // 释放资源
    fos.close();
    }
    }

写数据的换行和追加写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.itheima.outputstream_demo;

import java.io.FileOutputStream;
import java.io.IOException;

/*
字节流写数据的换行和追加写入

1 字节流写数据如何实现换行呢?
写完数据后,加换行符
windows : \r\n
linux : \n
mac : \r

2 字节流写数据如何实现追加写入呢?
通过构造方法 : public FileOutputStream(String name,boolean append)
创建文件输出流以指定的名称写入文件。如果第二个参数为true ,不会清空文件里面的内容
*/
public class OutputStreamDemo3 {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");

// void write(int b) 一次写一个字节数据
fos.write(97);
// 因为字节流无法写入一个字符串 , 把字符串转成字节数组写入
fos.write("\r\n".getBytes());
fos.write(98);
fos.write("\r\n".getBytes());
fos.write(99);
fos.write("\r\n".getBytes());

// 释放资源
fos.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.itheima.outputstream_demo;

import java.io.FileOutputStream;
import java.io.IOException;

/*
字节流写数据的换行和追加写入

1 字节流写数据如何实现换行呢?
写完数据后,加换行符
windows : \r\n
linux : \n
mac : \r

2 字节流写数据如何实现追加写入呢?
通过构造方法 : public FileOutputStream​(String name,boolean append)
创建文件输出流以指定的名称写入文件。如果第二个参数为true ,不会清空文件里面的内容
*/
public class OutputStreamDemo3 {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
// 追加写数据
// 通过构造方法 : public FileOutputStream​(String name,boolean append) : 追加写数据
FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt" , true);

// void write​(int b) 一次写一个字节数据
fos.write(97);
// 因为字节流无法写入一个字符串 , 把字符串转成字节数组写入
fos.write("\r\n".getBytes());
fos.write(98);
fos.write("\r\n".getBytes());
fos.write(99);
fos.write("\r\n".getBytes());

// 释放资源
fos.close();
}
// 写完数据换行操作
private static void method1() throws IOException {
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");

// void write​(int b) 一次写一个字节数据
fos.write(97);
// 因为字节流无法写入一个字符串 , 把字符串转成字节数组写入
fos.write("\r\n".getBytes());
fos.write(98);
fos.write("\r\n".getBytes());
fos.write(99);
fos.write("\r\n".getBytes());

// 释放资源
fos.close();
}
}

字节输入流

字节输入流介绍

字节输入流类

  • InputStream类 : 字节输入流最顶层的类 , 抽象类
    --- FileInputStream类 : FileInputStream extends InputStream
    

构造方法

  • public FileInputStream(File file) : 从file类型的路径中读取数据
  • public FileInputStream(String name) : 从字符串路径中读取数据

步骤

  • 创建输入流对象
  • 读数据
  • 释放资源

  • ```
    package com.itheima.inputstream_demo;

    import java.io.FileInputStream;
    import java.io.IOException;

    /*

    字节输入流写数据快速入门 : 一次读一个字节
            第一部分 : 字节输入流类
                InputStream类 : 字节输入流最顶层的类 , 抽象类
                --- FileInputStream类 : FileInputStream extends InputStream
            第二部分 : 构造方法
                public FileInputStream(File file) :  从file类型的路径中读取数据
                public FileInputStream(String name) : 从字符串路径中读取数据
            第三部分 : 字节输入流步骤
                1 创建输入流对象
                2 读数据
                3 释放资源
    

    */
    public class FileInputStreamDemo1 {

    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        // 读取的文件必须存在 , 不存在则报错
        FileInputStream fis = new FileInputStream("day11_demo\\a.txt");
    
        // 读数据 , 从文件中读到一个字节
        // 返回的是一个int类型的字节
        // 如果想看字符, 需要强转
        int by = fis.read();
        System.out.println((char) by);
    
        // 释放资源
        fis.close();
    }
    

    }

    1
    2
    3

    ### 字节输入流读多个字节

    package com.itheima.inputstream_demo;

import java.io.FileInputStream;
import java.io.IOException;

/
字节输入流写数据快速入门 : 读多个字节
第一部分 : 字节输入流类
InputStream类 : 字节输入流最顶层的类 , 抽象类
—- FileInputStream类 : FileInputStream extends InputStream
第二部分 : 构造方法
public FileInputStream(File file) : 从file类型的路径中读取数据
public FileInputStream(String name) : 从字符串路径中读取数据
第三部分 : 字节输入流步骤
1 创建输入流对象
2 读数据
3 释放资源
/
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
// 创建字节输入流对象
// 读取的文件必须存在 , 不存在则报错
FileInputStream fis = new FileInputStream(“day11_demo\a.txt”);

    // 读数据 , 从文件中读到一个字节
    // 返回的是一个int类型的字节
    // 如果想看字符, 需要强转

// int by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);
//
// by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);

    // 循环改进
    int by;// 记录每次读到的字节
    while ((by = fis.read()) != -1) {
        System.out.print((char) by);
    }

    // 释放资源
    fis.close();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

### 图片的拷贝

```java
package com.itheima.inputstream_demo;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
需求 : 把 "图片路径\xxx.jpg" 复制到当前模块下

分析:
复制文件,其实就把文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)
数据源:
xxx.jpg --- 读数据 --- FileInputStream
目的地:
模块名称\copy.jpg --- 写数据 --- FileOutputStream

*/
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
// 创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");

// 创建字节输出流
FileOutputStream fos = new FileOutputStream("day11_demo\\copy.jpg");

// 一次读写一个字节
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}

// 释放资源
fis.close();
fos.close();
}
}

异常的捕获处理

  • JDK7版本之前处理方式 : 手动释放资源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    package com.itheima.inputstream_demo;


    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /*
    需求 : 对上一个赋值图片的代码进行使用捕获方式处理
    */
    public class FileInputStreamDemo4 {
    public static void main(String[] args) {
    FileInputStream fis = null ;
    FileOutputStream fos = null;
    try {
    // 创建字节输入流对象
    fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");

    // 创建字节输出流
    fos = new FileOutputStream("day11_demo\\copy.jpg");

    // 一次读写一个字节
    int by;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    // 释放资源
    if(fis != null){
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    // 释放资源
    if(fos != null){
    try {
    fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }

  • JDK7版本优化处理方式 : 自动释放资源

    • JDK7优化后可以使用 try-with-resource 语句 , 该语句确保了每个资源在语句结束时自动关闭。
      简单理解 : 使用此语句,会自动释放资源 , 不需要自己在写finally代码块了

    • 格式 :

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      格式 :  
      try (创建流对象语句1 ; 创建流对象语句2 ...) {
      // 读写数据
      } catch (IOException e) {
      处理异常的代码...
      }

      举例 :
      try (
      FileInputStream fis1 = new FileInputStream("day11_demo\\a.txt") ;
      FileInputStream fis2 = new FileInputStream("day11_demo\\b.txt") )
      {
      // 读写数据
      } catch (IOException e) {
      处理异常的代码...
      }

  • 代码实践

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.itheima.inputstream_demo;

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /*
    JDK7版本优化处理方式

    需求 : 对上一个赋值图片的代码进行使用捕获方式处理
    */
    public class FileInputStreamDemo5 {
    public static void main(String[] args) {
    try (
    // 创建字节输入流对象
    FileInputStream fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");
    // 创建字节输出流
    FileOutputStream fos = new FileOutputStream("day11_demo\\copy.jpg")
    ) {
    // 一次读写一个字节
    int by;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
    // 释放资源 , 发现已经灰色 , 提示多余的代码 , 所以使用 try-with-resource 方式会自动关流
    // fis.close();
    // fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

字节输入流一次读一个字节数组

  • FileInputStream类 :

    • public int read(byte[] b) : 从输入流读取最多b.length个字节的数据, 返回的是真实读到的数据个数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    package com.itheima.inputstream_demo;


    import javax.sound.midi.Soundbank;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;

    /*
    FileInputStream类 :
    public int read​(byte[] b):
    1 从输入流读取最多b.length个字节的数据
    2 返回的是真实读到的数据个数
    */
    public class FileInputStreamDemo6 {
    public static void main(String[] args) throws IOException {
    // 创建字节输入流对象
    FileInputStream fis = new FileInputStream("day11_demo\\a.txt");

    // public int read​(byte[] b):
    // 1 从输入流读取最多b.length个字节的数据
    // 2 返回的是真实读到的数据个数

    byte[] bys = new byte[3];

    // int len = fis.read(bys);
    // System.out.println(len);// 3
    // System.out.println(new String(bys));// abc
    //
    // len = fis.read(bys);
    // System.out.println(len);// 2
    // System.out.println(new String(bys));// efc

    System.out.println("==========代码改进===============");

    // int len = fis.read(bys);
    // System.out.println(len);// 3
    // System.out.println(new String(bys, 0, len));// abc
    //
    // len = fis.read(bys);
    // System.out.println(len);// 2
    // System.out.println(new String(bys, 0, len));// ef

    System.out.println("==========代码改进===============");

    int len;
    while ((len = fis.read(bys)) != -1) {
    System.out.print(new String(bys , 0 , len));
    }

    fis.close();
    }
    }

  • 对复制图片的代码进行使用一次读写一个字节数组的方式进行改进

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    package com.itheima.inputstream_demo;


    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /*
    需求 : 对复制图片的代码进行使用一次读写一个字节数组的方式进行改进

    FileInputStream类 :
    public int read​(byte[] b):
    1 从输入流读取最多b.length个字节的数据
    2 返回的是真实读到的数据个数
    */
    public class FileInputStreamDemo7 {
    public static void main(String[] args) throws IOException {
    // 创建字节输入流对象
    FileInputStream fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");
    // 创建字节输出流
    FileOutputStream fos = new FileOutputStream("day11_demo\\copy.jpg");

    byte[] bys = new byte[1024];
    int len;// 每次真实读到数据的个数
    int by;
    while ((len = fis.read(bys)) != -1) {
    fos.write(bys, 0, len);
    }

    // 释放资源
    fis.close();
    fos.close();
    }
    }


代码案例

单字节数据读写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/28 21:15
* @Project JavaCode_SE_Advance
* @Theme 单字节数据读写
*/
public class CopyFile {
public static void main(String[] args) {

String srcFile = "day10/src/resources/222.jpeg"; //源数据文件
String destFile = "day10/src/demo/111.jpeg"; //目标文件

//计时
long startTime = System.currentTimeMillis();
copy(srcFile, destFile);
long endTile = System.currentTimeMillis();
System.out.println("复制花费了" + (endTile - startTime) + "毫秒");
}

/**
*
* @param srcFile 源数据文件地址
* @param destFile 目标文件地址
*/
private static void copy(String srcFile, String destFile) {

//创建输入输出流
//循环读取
//循环写入
try( FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile)){ //升级: 省略手动释放资源

int data = -1;
//未读完
while ((data = fis.read()) != -1){
fos.write(data); //读一个字节数据写一个字节数据
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/28 21:50
* @Project JavaCode_SE_Advance
* @Theme 多字节数据读写
*/
public class CopyFile2 {
public static void main(String[] args) {

String srcFile = "day10/src/resources/222.jpeg"; //源数据文件
String destFile = "day10/src/demo/demo2.txt"; //目标文件

//计时
long startTime = System.currentTimeMillis();
copy(srcFile, destFile);
long endTile = System.currentTimeMillis();
System.out.println("复制花费了" + (endTile - startTime) + "毫秒");
}

private static void copy(String srcFile, String destFile) {
try(FileInputStream fis = new FileInputStream(srcFile); //输入字节流
FileOutputStream fos = new FileOutputStream(destFile)){ //输出字节流

//字节数组
byte[] buf = new byte[1024]; //一次读取1k
int len = -1;
while ((len = fis.read(buf)) != -1){
fos.write(buf, 0, len);
}

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

}

字节缓冲流

在IO体系下,java提供了高效流(提高读写文件的效率)

字节缓冲流概述

  • 字节缓冲流:

    • ​ BufferOutputStream:缓冲输出流
    • ​ BufferedInputStream:缓冲输入流
  • 构造方法:

    • ​ 字节缓冲输出流:BufferedOutputStream(OutputStream out)
    • ​ 字节缓冲输入流:BufferedInputStream(InputStream in)
  • 为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

    • 字节缓冲流仅仅提供缓冲区,不具备读写功能 , 而真正的读写数据还得依靠基本的字节流对象进行操作

在IO体系下,java提供了高效流(提高读写文件的效率)

  • 读文件:BufferedInputStream
  • 写文件:BufferedOutputStream

创建:

在IO流中基础流只有两个:字节流、字符流

BufferedInputStream流的创建: 读数据

  • 自己没有读数据的能力,需要依赖字节输入流实现读数据
1
2
3
//构造方法: public  BufferedInputStream( InputStream  is )

BufferedInputStream bis = new BufferedInputStream( new FileInputStream("关联文件") );

BufferedOutputStream流的创建: 写数据

  • 自己没有写数据的能力,需要依赖字节输出流实现读数据
1
2
3
4
5
6
7
8
9
//构造方法: public  BufferedOutputStream( OutputStream  os )

//覆盖写入
BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("关联文件") );


//追加写入 (构造方法的第二个参数为true)
FileOutputStream fos = new FileOutputStream("关联文件" , true); //追加写入
BufferedOutputStream bos = new BufferedOutputStream( fos );//当前流有具有追加写入能力

image-20240429203842812

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package buffered;

import java.io.*;
import java.nio.file.FileVisitOption;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/29 19:54
* @Project JavaCode_SE_Advance
* @Theme 使用字节缓冲流进行文件复制
*/
public class CopyFile1 {
public static void main(String[] args) {
String srcFile = "day10/src/buffered/TwoAnimations.mp4"; //原文件
String destFile = "day10/src/buffered/CopyTwoAnimations.mp4"; //目标文件

//计时
long startTime = System.currentTimeMillis();
//文件复制
try {
copy(srcFile, destFile);
} catch (Exception e) {
e.printStackTrace();
}
//耗时
long endTime = System.currentTimeMillis();
System.out.println("总耗时" + (endTime - startTime) + "毫秒");



}

/**
*
* @param srcFile Sting类型的源文件
* @param destFile Sting类型的目标文件
*/
private static void copy(String srcFile, String destFile){
//读数据
//创建字节输入流
// 写数据
//创建字节输出流


//使用升级后的jdk功能
try {
//使用字节缓冲流
BufferedInputStream bfis = new BufferedInputStream( new FileInputStream(srcFile));
BufferedOutputStream bfos = new BufferedOutputStream( new FileOutputStream(destFile, true)); //追加写入
//2.循环读取
byte[] datas = new byte[1024]; //一次读取数据大小 1k
int len = -1; //初始化读取数据
// 判断是否读完,没完,写入
while ((len = bfis.read(datas)) != -1) { //为了方便写入数据所以初始化了data
bfos.write(datas, 0, len);
}
}catch (IOException e){
e.printStackTrace();
}
}
}

Properties集合类「重点!!!」

概述

  • properties是一个Map体系的集合类

    • public class Properties extends Hashtable <Object,Object>
  • 为什么在IO流部分学习Properties

    • Properties中有跟IO相关的方法
  • 当做双列集合使用

    • 不需要加泛型 , 工作中只存字符串

基本使用

Properties类:

  1. 作为Map集合的子类存在(存储的数据:key、value)
  2. 可以结合IO流使用 (读、写)

Properties类的基本使用:

  1. 作为集合使用
  2. 结合IO流使用

构造方法:

1
Properties prop = new Properties();

常用方法:

1
2
3
4
5
6
7
8
9
10
11
12
//向Properties集合中存储:key、value
setPorperty(String key , String value)

//根据指定的key,获取Properties集合中对应的value
String getProperty(String key)

//获取Properties集合中所有的key元素
Set<String> stringPropertyNames();

//借用字节输入流,读取配置文件,读取配置文件中的数据会存储到Properties集合中
//配置文件中的书写格式:key=value
load(InputStream is )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.itheima.properties_demo;

import java.util.Map;
import java.util.Properties;
import java.util.Set;

/*
1 properties是一个Map体系的集合类
- `public class Properties extends Hashtable <Object,Object>`
2 为什么在IO流部分学习Properties
- Properties中有跟IO相关的方法
3 当做双列集合使用
- 不需要加泛型 , 工作中只存字符串
*/
public class PropertiesDemo1 {
public static void main(String[] args) {
// 创建集合对象
Properties properties = new Properties();

// 添加元素
properties.put("it001" , "张三");
properties.put("it002" , "李四");
properties.put("it003" , "王五");

// 遍历集合 : 键找值
Set<Object> set = properties.keySet();
for (Object key : set) {
System.out.println(key + "---" + properties.get(key));
}

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

// 遍历集合 : 获取对对象集合 , 获取键和值
Set<Map.Entry<Object, Object>> set2 = properties.entrySet();
for (Map.Entry<Object, Object> entry : set2) {
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(key + "---" + value);
}
}
}

Properties作为集合的特有方法

  • Object setProperty(String key, String value) 设置集合的键和值,都是String类型,相当于put方法
  • String getProperty(String key) 使用此属性列表中指定的键搜索属性 , 相当于get方法
  • Set stringPropertyNames() 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 , 相当于keySet方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.itheima.properties_demo;

import java.util.Properties;
import java.util.Set;

/*
Properties作为集合的特有方法
Object setProperty(String key, String value) 设置集合的键和值,都是String类型,相当于put方法
String getProperty(String key) 使用此属性列表中指定的键搜索属性 , 相当于get方法
Set<String> stringPropertyNames​() 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 , 相当于keySet方法
*/
public class PropertiesDemo2 {

public static void main(String[] args) {
// 创建集合对象
Properties properties = new Properties();

// 添加元素
properties.setProperty("it001", "张三");
properties.setProperty("it002", "李四");
properties.setProperty("it003", "王五");

// 遍历集合 : 键找值
Set<String> set = properties.stringPropertyNames();
for (String key : set) {
System.out.println(key + "---" + properties.getProperty(key));
}
}
}

properties中和IO相关的方法

  • void load(InputStream inStream) 以字节流形式 , 把文件中的键值对, 读取到集合中
  • void load(Reader reader) 以字符流形式 , 把文件中的键值对, 读取到集合中
  • void store(OutputStream out, String comments) 把集合中的键值对,以字节流形式写入文件中 , 参数二为注释
  • void store(Writer writer, String comments) 把集合中的键值对,以字符流形式写入文件中 , 参数二为注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.itheima.properties_demo;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

/*
Properties和IO流结合的方法
void load​(InputStream inStream) 以字节流形式 , 把文件中的键值对, 读取到集合中
//void load​(Reader reader) 以字符流形式 , 把文件中的键值对, 读取到集合中
void store​(OutputStream out, String comments) 把集合中的键值对,以字节流形式写入文件中 , 参数二为注释
//void store​(Writer writer, String comments) 把集合中的键值对,以字符流形式写入文件中 , 参数二为注释
*/
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
// 创建Properties集合对象
Properties properties = new Properties();

// void load​(InputStream inStream) 以字节流形式 , 把文件中的键值对, 读取到集合中
properties.load(new FileInputStream("day11_demo\\prop.properties"));

// 打印集合中的数据
System.out.println(properties);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.itheima.properties_demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

/*
Properties和IO流结合的方法
void load​(InputStream inStream) 以字节流形式 , 把文件中的键值对, 读取到集合中
//void load​(Reader reader) 以字符流形式 , 把文件中的键值对, 读取到集合中
void store​(OutputStream out, String comments) 把集合中的键值对,以字节流形式写入文件中 , 参数二为注释
//void store​(Writer writer, String comments) 把集合中的键值对,以字符流形式写入文件中 , 参数二为注释
*/
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("zhangsan" , "23");
properties.setProperty("lisi" , "24");
properties.setProperty("wangwu" , "25");
properties.store(new FileOutputStream("day11_demo\\prop2.properties") , "userMessage");
}

private static void method1() throws IOException {
// 创建Properties集合对象
Properties properties = new Properties();

// void load​(InputStream inStream) 以字节流形式 , 把文件中的键值对, 读取到集合中
properties.load(new FileInputStream("day11_demo\\prop.properties"));

// 打印集合中的数据
System.out.println(properties);
}
}

补充

在开发中,通常会使用到配置文件,而配置文件格式通常分为:

  1. XML文件
  2. properties文件
  3. ….

Properties类的作用:

  • 读取开发中使用的到.properties配置文件
    • properties配置文件中的数据是以key/value形式体现
    • 把properties配置文件中的key,存储到Properties类中的key元素下
    • 把properties配置文件中的value,存储到Properties类中的value元素下

递归

什么是递归?

  • 递归是应用于方法上的解决方案:方法自己调用自己

递归 = 递进 + 回归

  • 递进 :前进
  • 回归: 后退

递归案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package digui;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/29 23:26
* @Project JavaCode_SE_Advance
* @Theme 递归案例
*/
public class Demo1 {
public static void main(String[] args) {
int x = 16;
System.out.println(factorial(x));
}

/**
* 用于计算整数阶乘
* @param x 整数x
* @return x的阶乘
*/
private static int factorial(int x) {
if (x == 1 || x == 0){
return 1;
}
return x * factorial(x - 1);
}
}

image-20240429233411482

递归的弊端:

  • 当递归调用的方法过多时,会造成栈内存的溢出

  • 解决方案: 队列结构

    1
    2
    3
    4
    5
    6
    7
    8
    1. 获取所有的File对象,存储到集合中
    2. 遍历集合
    判断:是文件
    判断:是否为java文件
    判断:是目录
    存储到集合中

    细节: 从集合中获取一个数据后,该数据在集合中就无用了

综合案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package digui;

import java.io.File;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/29 23:52
* @Project JavaCode_SE_Advance
* @Theme 综合案例: 打印给定文件夹下的所有java或者Python文件
*/
public class Demo2 {
public static void main(String[] args) {

//定义文件输入流
String strFile = "/users/ethan.liu/desktop/";
File file = new File(strFile);

String[] types = {"ppt", "java", "py", "docx", "zip"};
getSearchFile(file, types);
}

/***
*
* @param file 给定指定文件夹
* @param types 指定查询文件类型
* (以.结尾的文件扩展名
* eg:"py")
*/
private static void getSearchFile(File file, String[] types) {
//给定文件夹不存在, 抛出异常
if (!file.exists()) {
throw new RuntimeException("输入文件路径不存在");
}//存在,查找
else {
//获取文件元素列表
File[] files = file.listFiles();
//判断是文件还是文件夹
for (File f : files) {
if (f.isFile()) { //是文件, 查询
for (String type : types) {
if (f.getName().endsWith("." + type)) { //判断文件类型是否为指定文件类型
System.out.println(f.getAbsoluteFile()); //获取指定文件类型的绝对路径
}
}
} else if (f.isDirectory()) { //是文件夹, 递归调用方法
getSearchFile(f, types);
}
}
}
}
}