1. 程式人生 > 其它 >Java IO 常見類使用

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;