Loading

Java IO 常见类使用

Java IO 常见类使用

文件相关

遍历文件

File 类可以用于表示文件和目录的信息,但是它不表示文件的内容。

比如我要递归地列出一个目录下所有文件:

public static void listAllFiles(File dir) {
    if (dir == null || !dir.exists()) {
        return;
    }
    if (dir.isFile()) {
        System.out.println(dir.getName());
        return;
    }
    for (File file : dir.listFiles()) {
        listAllFiles(file);
    }
}

创建文件

创建文件的方式有很多,可以使用 File 对象、FileOutputStreamFiles 工具类,还可以使用一些封装好的工具包:

public static void main(String[] args) throws IOException {

    File file = new File("src/main/resources/myfile.txt");

    if (file.createNewFile()) {

        System.out.println("File has been created.");
    } else {

        System.out.println("File already exists.");
    }
}


public static void main(String[] args) throws FileNotFoundException, IOException {

    FileOutputStream fout = null;

    try {

        fout = new FileOutputStream("src/main/resources/myfile.txt");
    } finally {

        if (fout != null) {
            fout.close();
        }
    }
}

// 使用 Files 来创建,需要搭配 Path 对象
public static void main(String[] args) throws IOException {

    Path path = Paths.get("src/main/resources/myfile.txt");

    try {

        Files.createFile(path);

    } catch (FileAlreadyExistsException ex) {

        System.err.println("File already exists");
    }
}

字节流相关

public static void copyFile(String src, String dist) throws IOException {

    FileInputStream in = new FileInputStream(src);
    FileOutputStream out = new FileOutputStream(dist);
    byte[] buffer = new byte[20 * 1024];

    // read() 最多读取 buffer.length 个字节
    // 返回的是实际读取的个数
    // 返回 -1 的时候表示读到 eof,即文件尾
    while (in.read(buffer, 0, buffer.length) != -1) {
        out.write(buffer);
    }

    in.close();
    out.close();
}

逐行输出文本文件的内容

public static void readFileContent(String filePath) throws IOException {

    FileReader fileReader = new FileReader(filePath);
    BufferedReader bufferedReader = new BufferedReader(fileReader);

    String line;
    while ((line = bufferedReader.readLine()) != null) {
        System.out.println(line);
    }

    // 装饰者模式使得 BufferedReader 组合了一个 Reader 对象
    // 在调用 BufferedReader 的 close() 方法时会去调用 Reader 的 close() 方法
    // 因此只要一个 close() 调用即可
    bufferedReader.close();
}

序列化 & Serializable & transient

序列化就是将一个对象转换成字节序列,方便存储和传输。

  • 序列化: ObjectOutputStream.writeObject()
  • 反序列化: ObjectInputStream.readObject()

不会对静态变量进行序列化,因为序列化只是保存对象的状态,静态变量属于类的状态。

序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现,但是如果不去实现它的话而进行序列化,会抛出异常。


Serializable

public static void main(String[] args) throws IOException, ClassNotFoundException {
    A a1 = new A(123, "abc");
    String objectFile = "file/a1";
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(objectFile));
    objectOutputStream.writeObject(a1);
    objectOutputStream.close();

    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(objectFile));
    A a2 = (A) objectInputStream.readObject();
    objectInputStream.close();
    System.out.println(a2);
}

private static class A implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private int x;
    private String y;

    A(int x, String y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "x = " + x + "  " + "y = " + y;
    }
}

serialVersionUID

在 序列化存储/反序列化读取 或者是 序列化传输/反序列化接收 时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

在对实体类进行不影响业务流程的升级时,比如只追加了一个附加信息字段,可以不改变序列化版本号,来实现新旧实体类的兼容性(接收方的类里没有的字段被舍弃;多出来的字段赋初始值)。


transient

ArrayList 中存储数据的数组 elementData 是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。

private transient Object[] elementData;
posted @ 2022-05-19 17:20  槐下  阅读(28)  评论(0编辑  收藏  举报