JavaSE进阶九 IO流二

File类

  • File类和四大家族没有关系,所以File类不能完成文件的读和写。
  • File对象代表什么?
    • 文件和目录路径名的抽象表示形式。
    • 一个File对象有可能对应的是目录,也有可能是文件。
代码示例
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileTest01 {
    public static void main(String[] args)  {
        // 创建一个file对象  指定一个路径
        File file = new File("/Users/a1/Desktop/Java/Simon_JavaSE/test");
        // 判断该路径下文件是否存在
        System.out.println(file.exists());
        if (!file.exists()){ // 文件不存在,
            try {
                // 以文件的形式新建
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 以目录(文件夹)形式新建
            // file.mkdir();
        }

        File file1 = new File("/Users/a1/Desktop/Java/Simon_JavaSE/a/b/c/test.text");
        System.out.println(file1.exists());

        if (!file1.exists()){ // 不存在
            // 多重目录(文件夹)的形式新建
            file1.mkdirs();
        }

        // 获取文件的父路径
        String parentPath = file.getParent();
        System.out.println("获取父路径:" + parentPath);// /Users/a1/Desktop/Java/Simon_JavaSE
        File parentFile = file.getParentFile();
        System.out.println("获取绝对路径:" + parentFile.getAbsolutePath());

        // 获取绝对路径
        File file2 = new File("src/temp3");
        System.out.println("获取绝对路径:" + file2.getAbsolutePath());

        // 获取文件名
        System.out.println("文件名:" + file.getName());

        // 判断是否是一个目录
        System.out.println(file.isDirectory());
        // 判断是否是一个文件
        System.out.println(file.isFile());

        // 获取文件最后一次修改时间
        long hm = file.lastModified(); //从1970年到现在的总毫秒数
        Date time = new Date(hm);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String strTime = sdf.format(time);
        System.out.println(strTime);

        // 获取文件大小
        System.out.println(file.length());

        // 获取当前目录下所有的子文件
        File file4 = new File("/Users/a1/Desktop/Java/Simon_JavaSE");
        File[] fileList = file4.listFiles();
        // foreach
        for (File fl : fileList){
            System.out.println(fl.getAbsolutePath());
            System.out.println(fl.getName());
        }
    }
}
拷贝目录demo
import java.io.*;

public class CopyCatalogue {
    public static void main(String[] args) {
        // 拷贝源
        File srcFile =  new File("/Users/a1/Desktop/Java/Simon_JavaSE/JavaTest");
        // 拷贝目标
        File disFile =  new File("/Users/a1/Desktop/Java/Simon_JavaSE/JavaTest-Copy");
        // 调用方法进行拷贝
        copyDir(srcFile,disFile);
    }

    /**
     * 拷贝目录
     * @param srcFile 拷贝源
     * @param disFile 拷贝目标
     */
    private static void copyDir(File srcFile, File disFile) {
        if (srcFile.isFile()){
            // srcFile是一个文件时,递归结束。
            // 是文件需要拷贝,一边读一边写...
            FileInputStream fin = null;
            FileOutputStream fos = null;
            try {
                // 读取这个文件
                fin = new FileInputStream(srcFile);
                // 写到这个文件中
                String absolutePath = disFile.getAbsolutePath();
                String path = (absolutePath.endsWith("/") ? absolutePath: absolutePath + "/") + srcFile.getAbsolutePath().substring(45);
                fos = new FileOutputStream(path);

                // 一边读一边写
                byte[] bytes = new byte[1024 * 1024]; // 一次复制1MB
                int readCount = 0;
                while ((readCount = fin.read(bytes)) != -1){
                    fos.write(bytes,0,readCount);
                }

                // 刷新
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fin != null){
                    try {
                        fin.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fos != null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            return;
        }

        if (srcFile.isFile()){
            return;
        }
        // 获取拷贝源下面的子目录
        File[] files = srcFile.listFiles();
        for (File file : files){
            // 获取所有文件的绝对路径

            if (file.isDirectory()){
                String srcDir = file.getAbsolutePath();
                String disAbsolutePath = disFile.getAbsolutePath();
                String desDir = disAbsolutePath.endsWith("/") ? disAbsolutePath : disAbsolutePath + "/" + srcDir.substring(45);
                File newFile = new File(desDir);
                if (!newFile.exists()){
                    newFile.mkdirs();
                }
            }

            // 递归调用
            copyDir(file,disFile);
        }

    }
}

序列化和反序列化

  • 参与序列化和反序列化的对象,必须实现Serializable接口。

  • 通过源代码发现Serializable接口只是一个标志接口:

    • public interface Serializable{}
    • 这个接口当中什么代码都没有,起标识、标志的作用;java虚拟机看到这个类实现了这个接口,会对这个类进行特殊待遇。
    • Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化版本号。
  • transient关键字:

    • 表示游离的,不参与序列化。
  • java语言中是采用什么机制区分类的

    • 1,通过类名进行比对,如果类名不一样,肯定不是同一个类
    • 2,如果类名一样,靠序列化版本号进行区分。
  • 自动生成序列化版本号的缺陷:

    • 自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续修改,因为只有修改,必然会重新编译,
      此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。(如果没有重新序列化,
      只进行反序列化操作,会报异常)。
  • 开发中建议序列版本号手动写出,不建议自动生成。

代码示例
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class ObjectOutputStreamTest01 {
    public static void main(String[] args) {
        // 创建java对象
        Student student = new Student(1231,"张小五");
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;

        ObjectOutputStream oosList = null;
        ObjectInputStream oisList = null;
        try {
            // 序列化
            oos = new ObjectOutputStream(new FileOutputStream("Student"));
            // 序列化对象
            oos.writeObject(student);
            // 刷新
            oos.flush();

            // 反序列化 对象
            ois = new ObjectInputStream(new FileInputStream("Student"));
            // 开始反序列化
            Object obj = ois.readObject();
            System.out.println(obj);

            // ----------------------------------------------------------------------------

            // 序列化
            oosList = new ObjectOutputStream(new FileOutputStream("StudentList"));

            // 创建集合对象
            List list = new ArrayList<>();
            // 创建学生对象
            Student student1 = new Student(12,"张小六");
            Student student2 = new Student(13,"王小六");
            Student student3 = new Student(14,"李小六");
            Student student4 = new Student(15,"胡小六");
            // 添加元素
            list.add(student1);
            list.add(student2);
            list.add(student3);
            list.add(student4);

            // 序列化一个集合
            oosList.writeObject(list);
            // 刷新
            oosList.flush();

            // 反序列化集合
            oisList = new ObjectInputStream(new FileInputStream("StudentList"));
            Object redObj = oisList.readObject();
            // 开始反序列化
            if (redObj instanceof List){ // 如果是List集合
                // 进行类型转换
                List objs = (List) redObj;
                // 变量输出
                for (Student o : objs){
                    System.out.println(o);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (oosList != null){
                try {
                    oosList.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (oisList != null){
                try {
                    oisList.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class Student implements Serializable {
    // java虚拟机看到Serializable接口之后,会为该类自动生成一个序列化版本号。
    // 当Student这个类源代码改动了,需要重新编译,编译之后生成新的字节码文件。
    // 并且class文件再次运行的时候,java虚拟机生成的序列版本号也会发生相应的改变。

    // 如果没有重新序列化的时候,进行反序列化时会报异常。

    // 序列化版本号在没有手动写出的时候,系统会提供默认序列化版本号
    // 建议序列版本号手动写出,不建议自动生成
    private static final long serialVersionUID = 124234343342l;
    // idea工具 生成序列化版本号:" alt + 回车"

    private int no;
    // private String name;
    private transient String name; //name不参与序列化操作

    public Student() {
    }

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

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

IO+Properties的联合使用:

  • Properties是一个Map集合,key和value都是String类型。

  • 这种设计理念的好处:

    • 遇到经常要改动的数据,可以单独写到一个文件中,使用程序动态读取;将来只需要修改这个文件的内容,
      java代码不需要改动,不需要重新编译,服务器也不需要重启;就可以拿到动态信息。
  • 类似于以上机制的这种文件被称为配置文件。

    • 配置文件中的内容格式如下, 我们把这种配置文件称为:属性配置文件。

        key1=value
        key2=value
        ...
      
  • java规范中有要求:属性配置文件建议以.properties结尾,但不是必须的。

  • Properties是专门存放属性配置文件内容的一个类。(在属性配置文件中#是注释)

代码示例
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class IoPropertiesTest01 {
    public static void main(String[] args) {
        // 新建一个输入流对象
        FileReader reader = null;
        try {
            // 在src文件夹下新建一个userInfo文档
            // 内容填充: name=zhangsan  password=123466 (记得换行)
            reader = new FileReader("src/userInfo");

            // 新建一个Map集合
            Properties pro = new Properties();
            // 调用Properties对象的load方法将文件中的数据加载到Map集合中。
            pro.load(reader); //文件中的数据顺着管道加载到Map集合中:等号左边做key、右边做value
            // 通过key获取value
            System.out.println(pro.getProperty("name"));
            System.out.println(pro.getProperty("password"));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

上篇:JavaSE进阶九 IO流一

下篇:JavaSE进阶十 线程一

你可能感兴趣的:(JavaSE进阶九 IO流二)