Java-I/O框架

# 声明
本章所有代码用IDEA编写,
# 课程目标
1.流的概念
2.流的分类
3.字节流
4.编码方式
5.字符流
6.File类
# 1.什么是流
>一句话概括内容:理解流的概念
概念:内存与存储设备之间传输数据的通道。
tips:平时我们写的程序是运行在内存中,如new一个数组或者一个对象,或者一个基本类型的变量,我们知道这些内存中的东西只要程序关闭就会丢失,那么我们该如何保存呢?就是保存到硬盘中,此时数到硬盘之间的交互就需要一个通道,这个通道称为流。同样我们要想将数据从硬盘读取到内存一样需要一个通道。
tips:这里我们只需要理解通道的概念,至于这个通道该如何建立,那就是后面的事情啦!
# 2.流的分类
>一句话概括内容:按流向、方向
按流向
输入流:将**存储设备**中的内容读入到**内存**中;
输出流:将**内存**中的内容写入到**存储设备**中。
tips:这里的入和出是以内存为中心的。
按单位
字节流:以字节为单位,可以读写所有数据;
字符流:以字符为单位,智能读写文本数据。
tips:字节流是以字节为单位的,一个字节有8个bit位,而字符流是以字符位单位的,一个字符可能有多个字节组成,可能是1个、两个、三个等。
tips:为什么确定字符的字节个数不是确定的??自行百度!
按功能
字节流:具有实际传输数据的读写功能;
过滤流:在字节流的基础之上增强功能。
tips:这个先有个印象,不要深究。
# 3.字节流
>字节流是流按单位来分的一种,根据流向可以分为两种:字节输入流和字节输出流。现在我们来学习字节流的父类(抽象类),学习了父类,才可以更好的学习实现类。
InputStream:字节输入流
通过读取java API得知其常用的三个方法是:
1、public abstract int read() throws IOException
2、public int read(byte[] b) throws IOException
3、public int read(byte[] b,int off,int len) throws IOException
4、public void close() throws IOException==发方法用于关闭输入流,因为流的资源非常宝贵,用完要记得关闭,至于宝贵到哪里?你先记住宝贵就好了。
OutputStream:字节输出流
通过读取java API得知其常用的三个方法是:
1、public void write(int c) throws IOException
2、public void write(byte[] b) throws IOException
3、public void write(byte[] b,int off,int len) throws IOException
4、public void close() throws IOException
tips:InputStream和OutputStream抽象类是表示输入字节流和输出字节流的所有类的超类。上面这些方法看下,有个印象,用了之后要记住。
tips:需要注意的是,我们看过了抽象类,但在实际应用中,我们用的是实现类,这两个抽象类常用的实现类分别是FileInputStream和FileOutputStream。
FileInputStream:
public int read(byte[] b) throws IOException //从流中读取多个字节,将读到内容存入b数组,返回实际督导的字节数;如果达到文件的尾部,则返回-1。
如果想用该类,就要用构造方法创建对象,API中的构造方法有三个
 1 package com.yuncong.java_io;
 2 import java.io.FileInputStream;
 3 //该方法的异常正常情况下不是抛出的,而是用try-catch处理,这里为了看清,用throws抛出!
 4 public class Demo1 {
 5     public static void main(String[] args) throws Exception {
 6         FileInputStream fis = new FileInputStream("d:\\aaa.txt");
 7 
 8         int data;
 9         while ((data = fis.read()) != -1) {
10             System.out.println(data);
11         }
12         fis.close();
13     }
14 }

tips:对于上面的代码,我在D盘中新建了文件

 

tips:程序运行结果为:

 

tips:构造函数中的参数数String类型,表示的是文件路径,注意这里文件路径的写法。

tips:这里是一次读取一个字节相当于文件大小有多少个字节就得读取多少次数据,效率比较低下。read(byte[] b)可以一次读取的字节数是输入的参数数组的长度,相对于无参的read方法读取效率高出很多。下面进行演示:

 1 package com.yuncong.java_io;
 2 import java.io.FileInputStream;
 3 //一次读取多个字节放入byte数组中
 4 public class Demo2 {
 5     public static void main(String[] args) throws Exception {
 6         FileInputStream fis = new FileInputStream("d:\\aaa.txt");
 7 
 8         //注意:一般我们的缓存区不会这么小,常见比如1024
 9         byte[] bytes = new byte[2];
10 
11         int count;
12         while ((count = fis.read(bytes)) !=-1) {
13             System.out.println(new String(bytes,0,count));
14         }
15         fis.close();
16     }
17 }

tips:这里面有用到一个new String(bytes,0,count)的方法,作用是把数组bytes中从0-count长度的值转化为字符串。

tips:运行结果为我们可以发现这里出现了乱码现象,先不用管。

 

 

FileOutputStream:
public void write(byte[] b) throws IOException //一次写多个字符,将b数组中所有字节,写入输出流。
 1 package com.yuncong.java_io;
 2 import java.io.FileOutputStream;
 3 //一次写入一个字节
 4 public class FileOutputStreamDemo {
 5     public static void main(String[] args) throws Exception {
 6         FileOutputStream fos = new FileOutputStream("d:\\aaa.txt");
 7         fos.write(97);
 8         fos.write('b');
 9         fos.write(1);
10         fos.close();
11     }
12 }

tips:运行结果:其实我们看到,这个运行结果覆盖了原有的数据。

 

 

tips:这样一次写一个字节也麻烦,我们一次写一个字节型数组试试!

 1 package com.yuncong.java_io;
 2 import java.io.FileOutputStream;
 3 //一次写入一个byte型数组的数据
 4 public class FileOutputStreamDemo02 {
 5     public static void main(String[] args) throws Exception {
 6         FileOutputStream fos = new FileOutputStream("d:\\aaa.txt");
 7         fos.write("helloworld".getBytes());
 8         fos.close();
 9     }
10 }

tips:运行结果依然覆盖了原有的数据。

tips:当我们写出的时候,如果我们不想覆盖原有的数据怎么办??对于FileOutputStream有一个构造方法,append为true。

 1 package com.yuncong.java_io;
 2 import java.io.FileOutputStream;
 3 //一次写入一个byte型数组的数据
 4 public class FileOutputStreamDemo03 {
 5     public static void main(String[] args) throws Exception {
 6         FileOutputStream fos = new FileOutputStream("d:\\aaa.txt",true);
 7         fos.write("helloworld".getBytes());
 8         fos.close();
 9     }
10 }

tips:运行结果:

 

 

 

Java API获取链接:https://pan.baidu.com/s/113UuC3J6LZ08Otobt2a6bw
提取码:GJTT
复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V5的分享
 

实战演习

通过输入输出流实现文件的复制(这里的文件为一章图片)
 1 package com.yuncong.java_io;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.InputStream;
 5 import java.io.OutputStream;
 6 //字节输入输出流实战复制图片
 7 public class TestForInputAndOutputStream {
 8     public static void main(String[] args) throws Exception {
 9         InputStream fis = new FileInputStream("d:\\风景.png");
10         // 该复制文件本身不存在,此时会自动创建
11         OutputStream fos = new FileOutputStream("d:\\风景copy.png");
12         byte[] buff = new byte[1024];
13         int len; //用于保存实际读取的字节个数
14         // 边读边写,1024=1k,*2即2k
15         while ((len = fis.read(buff)) != -1) {
16             fos.write(buff,0,len);
17         }
18         fis.close();
19         fos.close();
20     }
21 }

tips:运行结果

 

字节缓冲区

缓冲流:BufferedInputStream/BufferedOutputStream

作用1:提高IO效率,减少访问磁盘的次数;

作用2:数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close。

BufferedInputStream

 1 package com.yuncong.java_io;
 2 import java.io.BufferedInputStream;
 3 import java.io.FileInputStream;
 4 import java.io.InputStream;
 5 //BufferedInputStream读取数据
 6 public class BufferedInputStreamDemo {
 7     public static void main(String[] args) throws Exception {
 8         FileInputStream fileInputStream = new FileInputStream("d:\\aaa.txt");
 9         InputStream bfi = new BufferedInputStream(new FileInputStream("d:\\aaa.txt"));
10         int data;
11         while ((data = bfi.read()) != -1) {
12             System.out.print((char)data);
13         }
14         //这个FileInputStream不用关,因为BufferedInputStream调用close时,底层帮他关了,关了也不错
15         //fileInputStream.close();
16         bfi.close();
17     }
18 }

d盘文件内容:

运行结果:

其实我们通过阅读BufferedInputStream的源码、可以发现其内部维护一个8K的缓冲区。

private static int DEFAULT_BUFFER_SIZE = 8192;
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}

 

 自定义一个缓冲区,自定义为1K的

 1 package com.yuncong.java_io;
 2 import java.io.BufferedInputStream;
 3 import java.io.FileInputStream;
 4 import java.io.InputStream;
 5 //BufferedInputStream读取数据
 6 public class BufferedInputStreamDemo02 {
 7     public static void main(String[] args) throws Exception {
 8         FileInputStream fileInputStream = new FileInputStream("d:\\aaa.txt");
 9         InputStream bfi = new BufferedInputStream(new FileInputStream("d:\\aaa.txt"));
10         int count;
11         byte[] bytes = new byte[1024];
12         while ((count = bfi.read(bytes)) != -1) {
13             System.out.print(bytes);
14         }
15         //这个FileInputStream不用关,因为BufferedInputStream调用close时,底层帮他关了,关了也不错
16         //fileInputStream.close();
17         bfi.close();
18     }
19 }

运行结果:

 

BufferedOutputStream

 1 package com.yuncong.java_io;
 2 import java.io.*;
 3 //BufferedInputStream读取数据
 4 public class BufferedOutputStreamDemo01 {
 5     public static void main(String[] args) throws Exception {
 6         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\aaa.txt"));
 7         byte[] bytes = new byte[1025];
 8         for (int i = 0; i < bytes.length; i++) {
 9             bytes[i] = (byte)(i % 255);
10         }
11         bos.write(bytes);
12         bos.flush();
13         //关闭(内部会调用flush方法,不过上面也可以写,万一断电没到这一步,上一步也可以保存一些)
14         //但其实我觉得吧,这个绝对不是写flush的原因,断电这种理由??
15         bos.close();
16     }
17 }

 运行结果:

 

 

对象流

对象流:ObjectOutputStream/ObjectInputStream

  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串功能
  • 增强了读写对象的功能
    • readObject():从流中读取一个对象
    • writeObject(Object obj):向流中写入一个对象

tips:使用流传输对象的过程称为序列化、反序列化。

 

ObjectOutputStream

通过读取API得知:

  1. ObjectOutputStream将Java对象的原始数据类型和对象写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。
  2. 该类的主要方法是write的重载方法,支持8中基本数据类型,String类型和对象类型
  3. 其它方法:flush方法和close方法

 现在用一个学生对象进行序列化(即写出文件)

package com.yuncong.java_io;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
//student代码时两个字段int age和string name,无参和有参构造,get和set方法,toString方法
public class ObjectOutputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:\\ccc.bin"));
        oos.writeObject(new Student(10,"张三"));
        // 注:ObjectOutputStream里面也有缓冲区,但是这里我没有调用flush,因为close时会自动调用该方法
        //此外,我也没有关闭FileOutputStream,因为关闭oos时,也会自动关闭
        oos.close();
    }
}

运行结果:报错,Exception in thread "main" java.io.NotSerializableException: com.yuncong.java_io.Student,这是说我们要用ObjectOutputStream写出Student对象,需要让Student类实现接口Serialiable接口(该接口是标识性接口,没有任何字段和方法)

修改后再次运行:

 

 ObjectInputStream

通过API得知:

  1. ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象;
  2. 构造方法为Protected ObjectInputStream(InputStream in);需要传入一个字节输入流,其是一个节点流
  3. 常用方法,读取字节,读取一个byte数组,读取基本类型,读取字符串,读取对象。

 

上面序列化后,我们再使用ObjectInputStream进行反序列化

 

package com.yuncong.java_io;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
// 反序列化
public class ObjectInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\ccc.bin"));
        Student o = (Student) ois.readObject();
        ois.close();
        System.out.println(o);
    }
}

运行结果:

 

 

序列化和反序列化注意事项

  •  序列化与反序列化的类必须实现Serializable接口,如果该类中有引用行属性(对象属性),则该类也要实现Serializable接口。
  • 使用transient(瞬间、瞬时)修饰属性,这个属性不能序列化
  • 静态属性不能序列化
  • 如何一次性序列化多个对象,如何反序列化多个对象(可以借助集合实现)


4.编码方式

  • ISO-8859-1:收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号;1个字节,表示共256个字符
  • UTF-8:针对Unicode码表的可变长度字符编码;1,2或3个字节,对应汉字的话,UTF-8是三个字节;
  • GB2312:简体中文;是95年前的国标,1或2个字节
  • GBK:简体中文,扩充,是95年后在GBK2312的基础上进行改进的国标,1或2个字节
  • BIG5:台湾,繁体中文

tips:当编码方式和解码方式一致时,会出现乱码。

5.字符流

这里用一段代码引入字符流,其实上面已经有了,我们看到上面程序输入或输出有乱码现象
package com.yuncong.java_io;
import java.io.FileInputStream;
//该方法的异常正常情况下不是抛出的,而是用try-catch处理,这里为了看清,用throws抛出!
public class FileInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("d:\\aaa.txt");
        int data;
        while ((data = fis.read()) != -1) {
            System.out.print((char) data + "~");
        }
        fis.close();
    }
}

 aaa.txt文本

 

 其编码方式为:

 

 运行结果为:

 

 tips:这里知道为什么解析出来是12个字节了吧??这同时也引出一个问题,像这种超过一个字节编码的文件,如果用字节流去读,并解析成一个字节,显然是乱码的,因此就要用字符流。

字符流的父类(抽象类)

Reader:字符输入流

  • public int read() {}
  • public int read(char[] c){}
  • public int read(char[] b,int off,int len){}

Writer:字节输出流

  • public void write(int n){}
  • public void write(String str){}
  • public void write(char[] c)

文件字符流

FileReader

  • public int read(char[] c) //从流中读取多个字符,将督导内容存入c数组,返回实际督导的字符数;如果达到文件的末尾,则返回-1。
package com.yuncong.java_io;
import java.io.FileReader;
public class FileReaderDemo {
    public static void main(String[] args) throws Exception {
        FileReader f = new FileReader("d:\\aaa.txt");
        int data;
        while ((data = f.read()) != -1) {
            System.out.print(data+"~");
            System.out.print((char)data);
            System.out.println();
        }
        f.close();
    }
}

运行结果:

 

 

其实这里我有一个很大的疑问?UTF-8编码中汉字是三个字节,但是Java中char是两个字节,那它是真没正确解析出汉字的??

上面是一次读取一个字节,现在我们创建一个缓冲区。

package com.yuncong.java_io;
import java.io.FileReader;
public class FileReaderDemo02 {
    public static void main(String[] args) throws Exception {
        FileReader f = new FileReader("d:\\aaa.txt");
        char[] buf = new char[1024];
        int count;
        while ((count = f.read(buf)) != -1) {
            for (int i = 0; i < count; i++) {
                System.out.print(buf[i] + "~");
            }
            System.out.println();
            System.out.println(new String(buf,0,count));
        }
        f.close();
    }
}

运行结果:

 

 tips:对于上面两个程序,你是否有疑问?为什么不是乱码呢??来,我马山刚给你演示一个乱码。

 

 修改后本地文件的编码方式后,再次运行:看这就是乱码。

 

这时候你明白为什么乱码吗??如果有机会,我课后习题会讲解清楚。当然其实有些地方我也不是很懂。 

 

 

FileWriter:

  • public void write(String str) // 一次写多个字符,将b数组中所有字符,写入输出流。
package com.yuncong.java_io;
import java.io.FileWriter;
public class FileWriterDemo01 {
    public static void main(String[] args) throws Exception {
        FileWriter fw = new FileWriter("d:\\aaa.txt");
        for (int i = 0; i < 10; i++) {
            fw.write("java是世界上最好的语言\r\n");
            fw.flush();
        }
        fw.close();
    }
}

 

运行结果:

 

 我这里解释以下以上中文为什么没有乱码!!以我个人的知识进行解释,比如FileWriter,从内存中写入到硬盘上,我们的代码默认用UTF-8编码,而txt文件也默认是UTF-8编码,因此没有乱码。

 
用字符流实现文件的复制
package com.yuncong.java_io;
import java.io.FileReader;
import java.io.FileWriter;
//使用字符流复制文本文件,但是不呢个复制图片、声音、视频等二进制文件。
public class TestForFileReaderAndWriter {
    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("d:\\aaa.txt");
        FileWriter fw = new FileWriter("d:\\bbb.txt");
        int data;
        while((data=fr.read()) != -1) {
            fw.write(data);
            //写的时候可以用下flush,我怎么感觉这个是不能拉下的??
            fw.flush();
        }
        fw.close();
        fr.close();
    }
}

 运行结果:

 

 

字符缓冲流

缓冲流:BufferedReader/BufferedWriter(其实就是实现借助缓冲提高读/写字符流的功能)

  • 高效读写(有缓冲区)
  • 支持输入换行符(newLine()方法,不用再写\r\n了)
  • 可一次写一行、读一行。

 

BufferedReader

package com.yuncong.java_io;
import java.io.BufferedReader;
import java.io.FileReader;
public class BufferedReaderDemo01 {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader("d:\\aaa.txt"));
        //自定义一个1K的缓冲区,如果不自定义,那么会用默认的8K
        char[] buf = new char[1024];
        int count;
        while ((count = br.read(buf)) != -1) {
            System.out.println(new String(buf,0,count));
        }
        br.close();
    }
}

 运行结果:

 

 对于使用默认的8K缓冲区,其实就是在上面的代码上不自定义缓冲区,这里就不演示了。我们演示以下一次读取一行。即readLine方法。

package com.yuncong.java_io;
import java.io.BufferedReader;
import java.io.FileReader;
public class BufferedReaderDemo02 {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader("d:\\aaa.txt"));
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    }
}

运行结果:和上面的一样效果,只是这个一次读一行,这里需要注意的是如果文本文件最后是空行,也是一样会读的。

BufferedWriter
package com.yuncong.java_io;
import java.io.BufferedWriter;
import java.io.FileWriter;
public class BufferedWriterDemo01 {
    public static void main(String[] args) throws Exception {
        BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\aaa.txt"));
        for (int i = 0; i < 10; i++) {
            //这里的换行符就不用这么写了
            //bw.write("你好呀!!aa\r\n");
            bw.write("你好呀!!aa");
            bw.newLine(); //这个可以根据你的操作系统来决定换行符windows \r\n linux \n
            bw.flush();
        }
        bw.close();
    }
}

 运行结果:

 

 

 打印流

PrintWriter:

  • 封装了print()/println()方法,支持写入后换行。
  • 支持数据原样打印
package com.yuncong.java_io;
import java.io.PrintWriter;
public class PrintWriterDemo01 {
    public static void main(String[] args) throws Exception {
        PrintWriter pw = new PrintWriter("d:\\aaa.txt");
        pw.write(97);
        pw.println(97);
        pw.println(true);
        pw.println(3.14);
        pw.println('a');
        //pw.flush(); 可省略
        pw.close();
    }
}

 运行结果:

 

 

转换流
桥转换流:InputStreamReader/OutputStreamWriter(名字就是字节流和字符流的抽象类的合成)
  • 可将字节流转换为字符流(内存中的文件都是字符形式的,硬盘中的文件都是二进制数据,即字节形式的)
  • 可设置字符的编码方式。

InputStreamReader

package com.yuncong.java_io;
import java.io.FileInputStream;
import java.io.InputStreamReader;
//读取文件,指定使用的编码
public class InputStreamReaderDemo01 {
    public static void main(String[] args) throws Exception {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\aaa.txt"), "utf-8");
        int data;
        while ((data = isr.read()) != -1) {
            System.out.print((char)data);
        }
        isr.close();
    }
}

运行结果:

 

 如果把这里修改为"gbk“,则乱码。那如何不乱码呢?要么程序改为utf-8,要么文本文件改为ANSI,这个意思是使用该国的编码,我们的国家就是GBK。

 

OutputStreamWriter

package com.yuncong.java_io;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class OutputStreamReaderDemo01 {
    public static void main(String[] args) throws Exception {
        OutputStreamWriter opw = new OutputStreamWriter(new FileOutputStream("d:\\aaa.txt"),"gbk");
        for (int i = 0; i < 10; i++) {
            opw.write("我的加!!12a\r\n");
            opw.flush();
        }
        opw.close();
    }
}

运行结果:

 

 

6.File类

前面我们学习了各种流的使用,比如字节流或字符流,我们知道使用流可以实现读取或写入文件内容。但是如果我们想删除一个文件、剪切一个文件或者修改文件的名字、获取文件创建的时间等,这样的话流就无法实现了。

概念:代表物理盘符中的一个文件或者文件夹。

方法:

package com.yuncong.java_io;

import java.io.File;
import java.util.Date;

/**
 * @author YCKJ-GaoJT
 * @create 2020-10-27 16:17
 **/
public class FileDemo01 {
    public static void main(String[] args) throws Exception {
        separator();
        System.out.println("===================");
        fileOpe();
        System.out.println("===================");
        directoryOpe();
    }
    //(1)分隔符
    public static void separator() {
        //作用一样,只是返回类型不一致
        System.out.println("路径分隔符"+ File.pathSeparator);
        System.out.println("路径分隔符"+ File.pathSeparatorChar);
        System.out.println("---------------------");
        System.out.println("名称分隔符"+File.separator);
        System.out.println("名称分隔符"+File.separatorChar);
    }
    //(2)文件操作
    public static void fileOpe() throws Exception {
        //1.创建文件
        File file = new File("d:\\newFile.txt");
        if (!file.exists()) {
            boolean b = file.createNewFile();
            System.out.println("创建结果:"+b);
        }
        System.out.println("-----------------");

        // 3.获取文件信息
        System.out.println("获取文件的绝对路径:"+file.getAbsolutePath());
        //这个是你写什么路径就是什么路径,我们这里写的是绝对路径,因此和上面显示一样
        //如果我们上面只是写"aaa.txtx",则该文件默认会在工程路径下创建,这里不再测试
        System.out.println("获取路径:"+file.getPath());
        System.out.println("获取文件名称:"+file.getName());
        System.out.println("获取父目录:"+file.getParent());
        System.out.println("获取文件大小:"+file.length());
        System.out.println("文件创建时间:"+new Date(file.lastModified()).toString());
        System.out.println("文件创建时间:"+new Date(file.lastModified()).toLocaleString());
        System.out.println("---------------------------");

        // 4.判断
        System.out.println("是否可写"+file.canWrite());
        System.out.println("是否是文件:"+file.isFile());
        System.out.println("是否隐藏:"+file.isHidden());
        System.out.println("-----------------");

        //2.删除文件,其实这连哥哥删除是有则删除,没有则不用管,不会报错,因此这里写了两个删除也没问题
        //2.1方式一:直接删除
        System.out.println("删除结果:"+file.delete());
        //2.2方式二:使用jvm要退出时删除
        file.deleteOnExit();

    }

    //(3)文件夹操作
    public static void directoryOpe() {
        //1.创建文件夹
        File dir = new File("d:\\aaa\\bbb\\ccc");
        if (!dir.exists()) {
            //System.out.println("创建结果:"+dir.mkdir()); mkdir只能创建单极目录
            System.out.println("创建结果:"+dir.mkdirs());// mkdirs创建多级目录
        }

        //3 获取文件夹信息
        System.out.println("获取绝对路径:" +dir.getAbsolutePath());
        System.out.println("获取路径:" +dir.getPath()); //写什么就获取到什么
        System.out.println("获取文件夹名称:"+dir.getName());
        System.out.println("获取父目录:"+dir.getParent());
        System.out.println("获取创建时间:" + new Date(dir.lastModified()).toLocaleString());

        //4 判断
        System.out.println("是否是文件夹:"+dir.isDirectory());
        System.out.println("是否是隐藏:"+dir.isHidden());

        //5 遍历文件夹
        File dir2 = new File("d:\\图片");
        String[] files = dir2.list(); //这个是将该文件夹西的所有文件和目录的名称放在String数组中返回
        File[] listFiles = dir2.listFiles();//这个是将该文件夹西的所有文件和目录封装成File文件,返回File数组
        for (String f:files) {
            System.out.println(f);
        }

        //2.删除文件夹
        //2.1直接删除,请注意,这个删除只能删除空文件夹,且只会删除最里层的文件夹,即上面的ccc文件夹。
        System.out.println("删除结果:"+dir.delete());
        //请注意,这个删除只能删除空文件夹,且只会删除最里层的文件夹,即上面的ccc文件夹。
        dir.deleteOnExit();
    }
}

运行结果:

 

现在补充一个接口的使用

FileFilter接口

  • public interface FileFilter
    • boolean accept(File pathname)

当调用File类中的listFiles()方法时,支持传入FileFilter接口实现类,对获取文件进行过滤,只有满足条件的文件的才可出现在listFiles()的返回值中。

 

 //5 遍历文件夹
        File dir2 = new File("d:\\图片");
        String[] files = dir2.list(); //这个是将该文件夹西的所有文件和目录的名称放在String数组中返回
        File[] listFiles = dir2.listFiles();//这个是将该文件夹西的所有文件和目录封装成File文件,返回File数组
        for (String f:files) {
            System.out.println(f);
        }

        System.out.println("--------FileFilter接口的使用-----------");
        File[] fi = dir2.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                if (pathname.getName().endsWith(".png")) {
                    return true; //return true;意思是该文件通过
                }
                return false;
            }
        });
        for(File f : fi) {
            System.out.println(f.getName());
        }

运行结果:

 

 案例

案例1:递归遍历文件夹,包括子文件夹中的所有文件

注释部分是我写的,竟然不对,看来我对递归的理解还是不深刻,肯定是哪里有了问题。

案例2:递归删除文件夹

delete是不能直接删除一个文件夹的,必须是这个文件夹存在且里面没有内容。

package com.yuncong.java_io;
import java.io.File;
public class TestForRecursivelyTraverseTheFolder {
    public static void main(String[] args) {
        listDir(new File("d:\\图片"));
        deleteDir(new File("d:\\图片"));
    }
    public static void listDir(File dir) {
        System.out.println(dir.getAbsolutePath());
        File[] files = dir.listFiles();
        if (files != null && files.length > 0) {
            for (File file : files) {
//                if (file.isFile()) {
//                    System.out.println(file.getAbsolutePath());
//                }else if (file.length() == 0) {
//                    System.out.println(file.getAbsolutePath());
//                }else {
//                    listDir(file);
//                }
                if (file.isDirectory()) {
                    listDir(file);
                }else {
                    System.out.println(file.getAbsolutePath());
                }
            }
        }
    }

    public static void deleteDir(File dir) {
        File[] files = dir.listFiles();
        if (files != null && files.length > 0) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDir(file);
                }else {
                    System.out.println(file.getAbsolutePath()+"删除:" + file.delete());
                }
            }
        }
        System.out.println(dir.getAbsolutePath()+"删除:" +dir.delete());
    }
}

运行结果:

 

 这里写以下对递归的理解:递归的本质是,不写了,写不清。

 

补充:Properties

Properties:属性集合(集成了HashTable,而且是一个线程安全的集合)

特点:

  • 存储属性名和属性值
  • 属性名和属性值都是字符串类型
  • 没有泛型
  • 和流有关
package com.yuncong.java_io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
    public static void main(String[] args) throws Exception {
        //1.创建集合
        Properties properties = new Properties();
        //2.添加数据
        properties.setProperty("userName","张三");
        properties.setProperty("age","28");
        System.out.println(properties.toString());
        //3.遍历
        //3.1----keySet------
        //3.2----entrySet------
        //3.3----stringPropertyNames()------
        Set<String> propertiesKeySet =  properties.stringPropertyNames();
        for (String key: propertiesKeySet) {
            System.out.println(key+"==="+properties.getProperty(key));
        }

        //4.和流有关的方法
        //========list==========
        PrintWriter pw = new PrintWriter("d:\\aaa.txt");
        properties.list(pw);
        pw.close();
        //========2.store方法保存==========
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\aaa.properties");
        properties.store(fileOutputStream,"注释内容");
        fileOutputStream.close();

        //========3.load方法加载(后面用的最多)==========
        Properties p2 = new Properties();
        FileInputStream fileInputStream = new FileInputStream("d:\\aaa.properties");
        p2.load(fileInputStream);
        fileInputStream.close();
        System.out.println(p2.toString());

    }
}

 

 运行结果:

 

 

 

 

 

 

 

总结

>阅读了上述博客,你必须背会的知识点!!其它知识点你只需要有印象即可,不记得也没有关系。
此外,请注意,如果你是第一次学习,我相信有许多概念你还是不是很清楚,那都没有关系,但是下面的知识点必须背会!!!

记住

字节流及其常用实现类

1.字节流是什么?

2.字节流的抽象父类是哪两个?

3.抽象父类中的常用方法是什么?

4.这两个抽象父类的常用实现子类是什么?文件字节流

5.上文中举例FileInputStream类的两个代码分别实现了什么功能?区别是什么?请默写出该代码。

6.上文中举例FileOutputStream类的两个代码分别实现了什么功能?区别是什么?请默写出该代码。

7.上文中用文件字节流实现了文件的copy,请默写出该代码。

8.对于字节流抽象类、文件字节流实现类应该掌握的方法和构造方法是什么?请列出出来。

9.什么是节点流?什么是处理流?请分别举例,并说明你对节点流和处理流的理解。

10.对象流

11.ObjectOutputStream写入对象到硬盘需要多注意点是什么?

如果写的时候没有这个文件会怎么办?自动创建

无论是字节流还是字符流,写出的时候是可以flush的,那么这个flush写不写??

什么是二进制文件,什么是文本文件?

“硬盘上的所有文件都是二进制数据保存的,字节流可以复制任意文件,而字符流智能复制文本文件,不能复制图片等二进制文件。”这句话如何理解?

“文本文件是有字符编码的,而图片、视频等二进制流是没有编码的。”这句话怎么理解?

如果使用处理流,那么被包装的节点流可以不用close方法吗??为什么?

BufferedWriter支持换行方法是什么?有什么优势。

PrintWriter与其它字符输出流的区别,或者说其优势是什么??

转换流的作用是什么?其有什么独到的地方?可以设置编码,之前的只能是默认编码。

描述出本博客的所有内容。

File file = new File("d:\\aaa.txt");怎么理解这句话,这段代码执行后是否是在d盘下创建了aaa.txtx文件?

File file = new File("d:\\aaa.txt"); boolean b = file.createNewFile();怎么理解这段话,这段话执行后是在d盘下创建了aaa.txtx文件吗?不一定。如果创建失败,返回什么?

File需要掌握的字段和方法。

## 理解
posted @ 2020-10-26 19:43  峡谷挨打记  阅读(122)  评论(0编辑  收藏  举报