5.Java中的IO流、File类和序列化

一.File类

1.概述:

  •  java.io.File :是文件和目录路径类,用于对文件和目录的创建、查找和删除等操作

2.File类的四个静态成员变量:

  •  public static final char separatorChar :文件名称分隔符的字符表示
  •  public static final String separator :文件名称分隔符的字符串表示
  •  public static final char pathSeparatorChar :路径分隔符的字符表示
  •  public static final String pathSeparator :路径分隔符的字符串表示
 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4 
 5         String pathSeparator = File.pathSeparator; //路径分隔符:windows中是分号,Linux中是冒号
 6         System.out.println(pathSeparator);
 7 
 8         String separator = File.separator;  //文件名称分隔符:windows中是反斜杠,Linux中是正斜杠
 9         System.out.println(separator);
10     }
11 }

注意:操作路径不能写死(不同操作系统符号不同)
一般写法:“C:"+File.separator+"xxx"+File.separator+"xxx.xx"

补充知识:相对路径和绝对路径

  • 绝对路径:是一个完整地路径,以盘符开始的路径。例如:D:\\Project\\Java\\Demo\\test.txt

  • 相对路径:是一个简化的路径,指的是相对于当前项目的根目录的路径,省略了项目的根目录名称。例如文件的根目录为D:\\Project\\Java\\Demo,则简写test.txt

  • 注意:

    • 路径是不区分大小写的

    • 路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠。

3.File类的四个构造方法

  •  public File(String pathname) :输入路径字符串名称,创建一个新的File实例
  •  public File(String parent, String child) :输入父路径和子路径字符串名称,创建一个新的File实例
  •  public File(File parent, String child) :输入父路径为文件的对象和子路径字符串名称,创建一个新的File实例,优点:可以操作父路径文件对象
  •  public File(URI uri) :输入一个URI来创建一个新的File实例

 

 1 public class demo02 {
 2 
 3     public static void main(String[] args) {
 4         File file1 = new File("C:\\Demo");
 5         System.out.println(file1);  //C:\Demo
 6         File file2 = new File("C:\\Demo\\", "test.txt");
 7         System.out.println(file2);  //C:\Demo\test.txt
 8         File file3 = new File(file2, "text.txt");
 9         System.out.println(file3);  //C:\Demo\test.txt\text.txt
10     }
11 }

 

4.File类的普通方法

  • 获取功能的方法:

    •  public String getAbsolutePath() :返回此File的绝对路径字符串,输出连同盘符的路径名。
    •  public String getPath() :将此File转换为路径名字符串,创建时对象是什么名称,输出就是什么名称。(File的toString方法内部调用此方法输出
    •  public String getName() :返回由此File表示的文件或目录的名称。获取路径结尾部分的文件或文件夹名称。
    •  public long length() :返回由此File表示的文件的长度。也就是返回文件或文件夹大小,以字节为单位,当文件和文件夹不存在时返回0。

 

 1 public class demo03 {
 2     public static void main(String[] args) {
 3 
 4         File file1 = new File("D:\\Demo\\Java\\test.txt");
 5         System.out.println(file1.getAbsolutePath());    //D:\Demo\Java\test.txt
 6         System.out.println(file1.getPath());            //D:\Demo\Java\test.txt
 7         System.out.println(file1.getName());            //test.txt
 8         System.out.println(file1.length());             //0
 9 
10         File file2 = new File("aaa.txt");
11         System.out.println(file2.getAbsolutePath());    //F:\Java\Test\aaa.txt
12         System.out.println(file2.getPath());            //aaa.txt
13         System.out.println(file2.getName());            //aaa.text
14         System.out.println(file2.length());             //797854
15     }
16 }
  •  判断功能的方法:

    • public boolean exists() :判断文件或目录是否存在
    • public boolean isDirectory() :判断是否为一个目录
    • public boolean isFile() :判断是否为一个文件
1 public class demo04 {
2     public static void main(String[] args) {
3 
4         File file1 = new File("src");
5         System.out.println(file1.exists());         //true
6         System.out.println(file1.isDirectory());    //true
7         System.out.println(file1.isFile());         //false
8     }
9 }
  • 创建和删除功能的方法:

    •  public boolean createNewFile() :当文件名称不存在时创建一个新的文件。

    •  public boolean delete() :删除文件或目录(只能删除一个单级文件夹,删除成功返回true,当删除的文件夹中有文件则不删除返回false)
    •  public boolean mkdir() :创建一个目录,只能创建单级文件夹。(文件夹存在或创建路径错误则返回false)
    •  public boolean mkdirs() :创建一个文件目录,能够创建多级文件夹
 1 public class demo04 {
 2     public static void main(String[] args) throws IOException {
 3 
 4         File file1 = new File("testFile.txt");
 5         System.out.println(file1.createNewFile());      //true
 6         System.out.println(file1.delete());             //true
 7 
 8         file1 = new File("testDir");
 9         System.out.println(file1.mkdir());              //true
10         System.out.println(file1.delete());             //true
11 
12         file1 = new File("testDir\\testDir1\\testDir2\\testDir3");
13         System.out.println(file1.mkdirs());             //true
14         System.out.println(file1.delete());             //true
15     }
16 }

5.目录的遍历

  •  public String[] list() :返回String数组,表示目录中的所有子文件和目录(不嵌套内部目录中的文件或目录)
  •  public File[] listFiles() :返回File数组,表示目录中的所有子文件和目录(不嵌套内部目录中的文件或目录)
  • 注意:
    • 根据构造函数给出的路径遍历,当目录的路径不存在,会抛出空指针异常
    • 当路径不是目录时,抛出空指针异常
 1 public class demo04 {
 2     public static void main(String[] args) throws IOException {
 3 
 4         File file1 = new File("F:\\java_code");
 5 
 6         for (String s : file1.list()) {
 7             System.out.println(s);      //common_java  testDir
 8         }
 9 
10         for (File f : file1.listFiles()) {
11             System.out.println(f);  //F:\java_code\common_java  F:\java_code\testDir
12         }
13     }
14 }

6.案例:递归打印多级文件目录

 1 public class demo04 {
 2 
 3     public static void getAllFile(File file) {
 4         if (file.isDirectory()) {
 5             for (File f : file.listFiles()) {
 6                 if (f.isDirectory()) {
 7                     getAllFile(f);
 8                 } else {
 9                     System.out.println(f);
10                 }
11             }
12         }
13         else {
14             System.out.println(file);
15         }
16     }
17 
18     public static void main(String[] args) throws IOException {
19 
20         File file1 = new File("F:\\java_code");
21         getAllFile(file1);
22 
23     }
24 }

 7.文件过滤器实现过滤文件

  • File类中有两个与listFiles重载的方法,参数为过滤器:
    • public File[] listFiles(FilenameFilter filter) :
    • public File[] listFiles(FileFilter filter :
  • java.io.FileFilter 接口:用于File对象的过滤器
    • 唯一的抽象方法: boolean accept(File pathname) ,参数为File对象
  • java.io.FilenameFilter 接口:用于过滤文件名称
    • 唯一的抽象方法:boolean accept(File dir, String name) ,参数为需要遍历的目录,获取到的遍历目录中每一个文件或文件夹的名称
  • 两个过滤器没有实现类,需要我们自己实现过滤器的accept方法,来实现自定义的规则。

实现将目录中递归搜索所有以.class结尾的文件,使用两种过滤器

 1 public class demo04 {
 2 
 3     // 1.使用FileFilter来递归获得文件后缀名为.class的文件
 4     public static void getAllFile1(File file) {
 5         //当file目录中有文件夹或以.class结尾的文件则放入文件数组中保存
 6         File[] files = file.listFiles(pathname -> pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".class"));
 7 
 8         for (File f : files) {
 9             if (f.isDirectory()) {
10                 getAllFile1(f);
11             } else {
12                 System.out.println(f);
13             }
14         }
15     }
16 
17     // 2.使用FilenameFilter来递归获得文件后缀名为.class的文件
18     public static void getAllFile2(File file) {
19         //当file目录中有文件夹或以.class结尾的文件则放入文件数组中保存
20         File[] files = file.listFiles((dir,name) -> new File(dir,name).isDirectory() || name.toLowerCase().endsWith(".class"));
21 
22         for (File f : files) {
23             if (f.isDirectory()) {
24                 getAllFile1(f);
25             } else {
26                 System.out.println(f);
27             }
28         }
29     }
30 
31     public static void main(String[] args) throws IOException {
32 
33         File file1 = new File("F:\\java_code");
34         getAllFile1(file1);
35         System.out.println("================================");
36         getAllFile2(file1);
37 
38     }
39 }

 二.IO流

1.IO的分类

根据数据的流向分为:输入流和输出流

  • 输入流:把数据从其他设备上读取到内存中的流
  • 输出流:把数据从内存中写到其他设备上的流

数据的类型分为:字节流和字符流

流:数据(字符或字节) 1个字符 = 2个字节 ,1个字节= 8个二进制位,中文占3个字节

  输入流 输出流
字节流 字节输入流InputStream 字节输出流OutputStream
字符流 字符输入流Reader 字符输出流Writer

2.字节流:读取中文会有乱码,请使用字符流

【1】一切皆为字节

    一切文件数据都是以二进制数字的形式保存。字节流可以传输任意文件数据,我们时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

【2】字节输出流[OutputStream]

  • FileOutputStream

public void test1() throws IOException{
    FileOutputStream fos = new FileOutputStream("src/code/a.txt");
    //1.写一个字节到文件中
    fos.write(97); //将十进制转换为二进制数据,97 = 'a'

    //2.写多个字节
    //当写入多个字节时,第一个字节是正数(0~127之内),那么会查询ASCII表
    fos.write(new byte[]{65,66,67,68,69});      //ABCDE

    //当写入多个字节时,第一个字节为负数,则第一个字节和第二个字节会组成一个中文显示,查询系统默认码表(GBK)
    fos.write(new byte[]{65,-66,-67,68,69});    //A窘DE

    //写字节数组的部分
    byte[] bytes = {65,66,67,68,69};
    fos.write(bytes,1,2);

    //将字符串变成字节写入
    fos.write("你好!".getBytes());

    fos.close();
}
public static void test2() throws IOException{
    //追加写并换行
    FileOutputStream fos = new FileOutputStream("src/code/a.txt",true);

    fos.write("你好!".getBytes());
    fos.write("\r\n".getBytes());  //windows:\r\n   linux:/n     mac:/r
    fos.write("你好!".getBytes());

    fos.close();
}

【3】InputStream

  • FileInputStream

public static void test3() throws IOException {
    FileInputStream fis = new FileInputStream("src/code/a.txt");

    //1.读取一个字节
    int i = fis.read();
    System.out.println(i);  //读到'a'会变为int类型为97,读到末尾返回-1

    //2.循环读取到文件结尾,一次读取一个字节
    int len1 = -1;
    while((len1 = fis.read()) != -1){
        System.out.println((char) len1);
    }

    //3.一次读取多个字节
    byte[] bytes = new byte[10];
    int len2 = fis.read(bytes); //将读取到的放在bytes,将读取到的长度返回
    System.out.println(len2);   //读取到的有效字节个数
    //返回数据(包含无效空格和前一次读取的脏数据
    //【例如之前赋值了byte[6],这次有效数据只有3个,那么byte[6]的数据就是脏数据】)
    System.out.println(new String(bytes));

    //循环读取有效数据
    int len3 = -1;
    while ((len3 = fis.read(bytes)) != -1) {
        System.out.println(new String(bytes, 0, len3)); //将有效数据转化为String
    }

    fis.close();
}

【4】字节流练习:图片复制

public static void test4() throws IOException {
    long start = System.currentTimeMillis();

    FileInputStream fis = new FileInputStream("src/code/1.png");
    FileOutputStream fos = new FileOutputStream("src/code/图片.png");

    byte[] bytes = new byte[1024];
    int len = -1;
    while ((len = fis.read(bytes)) != -1) {
        fos.write(bytes, 0, len);
    }


    fis.close();
    fos.close();
    long end = System.currentTimeMillis();

    System.out.println("消耗时间:" + (end - start) + "ms");

}

3.字符流

  • 使用字节流读取中文字符时会产生错误,所以我们以字符为单位,专门处理文本文件

【1】Reader

  •  FileReader

public static void test5() throws IOException {

    FileReader fr = new FileReader("src/code/a.txt");

    //1.一个字符读取
    int len;
    while((len = fr.read()) != -1){
        System.out.println((char) len);
    }

    //2.读取多个字符
    char[] chars = new char[1024];
    while ((len = fr.read(chars))!=-1){
        System.out.println(new String(chars,0,len));
    }

    fr.close();
}

【2】Writer

 

  • FileWriter

public static void test6() throws IOException {

    FileWriter fw = new FileWriter("src/code/b.txt");

    //1.写单个字符
    fw.write(97);
    fw.flush(); //将内存缓冲区的数据刷新到文件中

    fw.close(); //也拥有flush功能(可以省略fw.flush())但会关闭流就不能使用流了
}
public static void test7() throws IOException {

    FileWriter fw = new FileWriter("src/code/b.txt");

    //1.写整个字符数组
    char[] chars = {'a','b','c','d'};
    fw.write(chars);
    
    //2.写部分字符数组
    fw.write(chars,1,3);    //bcd
    
    //3.写一个字符串
    fw.write("你好!");

    fw.close();
}
public static void test8() throws IOException {

    //追加写
    FileWriter fw = new FileWriter("src/code/b.txt",true);

    //换行
    fw.write("你好!\r\n");
    fw.write("Hello World!");

    fw.close();
}

流的异常处理:

public static void test9() {
    
    FileWriter fw = null;
    try {
        fw = new FileWriter("src/code/b.txt", true);
        fw.write("Hello World!");
    } catch (IOException e) {
        System.out.println(e);
    } finally {
        //判断对象是否创建成功
        if (fw != null) {
            try {
                fw.close();
            } catch (IOException e) {
                System.out.println(e);
            }
        }
    }
}

JDK7的版本:由于实现了AutoCloseable接口的close方法

public static void test10() {

    try (FileWriter fw = new FileWriter("src/code/b.txt", true)) {
        fw.write("Hello World!");
    } catch (IOException e) {
        System.out.println(e);
    }
}

4.Properties

【1】基本使用

public static void test11() {

    Properties prop = new Properties();

    prop.setProperty("id=1","小明");
    prop.setProperty("id=2","小洪");
    prop.setProperty("id=3","小花");

    Set<String> set = prop.stringPropertyNames();

    for (String key : set) {
        System.out.println(key + ":" + prop.getProperty(key));
    }
}

【2】store方法

 

  • 字符流可以写中文

public static void test12() throws IOException {

    Properties prop = new Properties();

    prop.setProperty("id=1","小明");
    prop.setProperty("id=2","小洪");
    prop.setProperty("id=3","小花");

    FileWriter fw = new FileWriter("src/code/b.txt");

    prop.store(fw,"save data");

    fw.close();
}
  • 字节流写中文乱码

public static void test13() throws IOException {

    Properties prop = new Properties();

    prop.setProperty("id=1","小明");
    prop.setProperty("id=2","小洪");
    prop.setProperty("id=3","小花");

    prop.store(new FileOutputStream("src/code/b.txt"),"");
}

【3】load方法

需要用字符流读取不要用字节流读取

public static void test14() throws IOException {

    Properties prop = new Properties();

    prop.load(new FileReader("src/code/b.txt"));

    Set<String> set = prop.stringPropertyNames();

    for (String key : set) {
        System.out.println(key + ":" + prop.getProperty(key));
    }
}

5.缓冲流

  • 目的是提高读写速度

【1】BufferedOutputStream

  • 关闭缓冲流会自动把输入输出流都关闭了,所以使用到的输入输出流不需要再次关闭了

public static void test15() throws IOException {

    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src/code/c.txt"));

    bos.write("小王".getBytes());

    bos.flush();

    bos.close(); //释放资源之前会先调用flush方法,再释放
}

【2】BufferedInputStream

public static void test16() throws IOException {

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/code/c.txt"));

    //每次读一个
//        int len = 0;
//        while ((len = bis.read()) != -1) {
//            System.out.println(len);
//        }

    // 读取一批
    byte[] bytes = new byte[1024];
    int len = 0;
    while ((len = bis.read(bytes)) != -1) {
        System.out.println(new String(bytes, 0, len));
    }

    bis.close(); //释放资源之前会先调用flush方法,再释放
}

【3】读写图片

public static void test17() throws IOException {

    long start = System.currentTimeMillis();
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src/code/3.png"));
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/code/1.png"));

    // 读取一批
    byte[] bytes = new byte[1024];
    int len = 0;
    while ((len = bis.read(bytes)) != -1) {
        bos.write(bytes, 0, len);
    }

    bis.close();
    bos.close();
    long end = System.currentTimeMillis();

    System.out.println("消耗时间:" + (end - start) + "ms");
}

【4】BufferedWrite

public static void test18() throws IOException {
    BufferedWriter bw = new BufferedWriter(new FileWriter("src/code/c.txt"));

    bw.write("你好");
    bw.newLine();
    bw.write("Hello World");

    bw.close();
}

【5】BufferedReader

public static void test19() throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("src/code/c.txt"));

    //1.读一行,返回数据不包含换行符,读到末尾返回null
//        String line = br.readLine();
//        System.out.println(line);

    //2.循环读取
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }

    br.close();
}

6.转换流

  • 指定编码表,来解决编码格式不同而产生的乱码问题

【1】OutputStreamWriter

public static void test20() throws IOException{

    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("src/code/c.txt"),"utf-8");

    osw.write("明明");

    osw.flush();
    osw.close();
}

【2】InputStreamReader

public static void test21() throws IOException{

    InputStreamReader isw = new InputStreamReader(new FileInputStream("src/code/c.txt"),"utf-8");

    int len = 0;
    while((len = isw.read()) != -1){
        System.out.println((char) len);
    }

    isw.close();
}

三.序列化

import java.io.Serializable;

public class Person implements Serializable {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

1.ObjectOutputStream

public static void test22() throws IOException{

    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/code/c.txt"));

    oos.writeObject(new Person("小王",25));

    oos.close();
}

2.ObjectInputStream

public static void test23() throws IOException, ClassNotFoundException {

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/code/c.txt"));

    Object o = ois.readObject();

    ois.close();

    System.out.println(o);
}

3.transient关键字

  • 加上transient关键字的属性不能被序列化

  • static关键字同样的属性不能被序列化

4.反序列化失败的案例

  • 序列号不同导致

  • 手动增加一个序列号,用来防止属性修改而导致的反序列化失败

private static final long serialVersionUID = 1L;

四.打印流

1.PrintStream

 

public static void test24() throws FileNotFoundException {

    PrintStream ps = new PrintStream("src/code/c.txt");

    ps.write(97);   //使用write会将97会变成 ’a'

    ps.println(97);     //使用println会原样输出并换行
    ps.println(8.8);
    ps.println('c');
    ps.println(true);
    ps.println("Hello World");

    ps.close();
}

2.改变输出语句的目的地

  • 将在控制台输出的语句输出到文本中

public static void test25() throws FileNotFoundException {

    System.out.println("控制台输出############");

    PrintStream ps = new PrintStream("src/code/c.txt");

    System.setOut(ps); //修改输出的目的地

    System.out.println("修改了输出的目的地到文本中");

    ps.close();
}

 

posted @ 2019-12-30 00:34  All_just_for_fun  阅读(299)  评论(0编辑  收藏  举报