1. 類別 File:一切的開始
雖然我們已經得出結論,新專案最好不要使用 File 類別,但仍有大量既有系統在使用它,因此理解並能運用它很重要。File 是在磁碟上表示檔案或目錄的舊方式。但別混淆:File 物件本身不是檔案,只是路徑的「指標」/身分。舉例來說,表達式 File f = new File("hello.txt"); 並不會在磁碟上建立檔案——你只是描述了路徑。
如何建立 File 物件?
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
File file = new File("example.txt"); // 相對路徑
File folder = new File("mydir"); // 目錄
System.out.println("絕對路徑: " + file.getAbsolutePath());
System.out.println("檔案是否存在? " + file.exists());
System.out.println("是檔案嗎? " + file.isFile());
System.out.println("是目錄嗎? " + folder.isDirectory());
}
}
要點:
建立 File 物件不會在磁碟上建立檔案。它只是「捷徑」。若要讓檔案實際存在,必須明確地觸發建立(例如寫入資料,或呼叫 file.createNewFile())。
File 類別的主要方法
- exists() — 檢查檔案/目錄是否存在。
- isFile() — 是否為檔案(而非資料夾)。
- isDirectory() — 是否為目錄。
- getAbsolutePath() — 取得絕對路徑。
- length() — 檔案大小(位元組)。
- getName() — 檔案或資料夾名稱。
- delete() — 刪除檔案/目錄(若為空)。
範例:輸出檔案資訊
File file = new File("example.txt");
System.out.println("名稱: " + file.getName());
System.out.println("路徑: " + file.getAbsolutePath());
System.out.println("大小: " + file.length() + " 位元組");
System.out.println("存在嗎? " + file.exists());
2. 類別 Path:現代的檔案觀
Path 是新的檔案 API(NIO.2,自 Java 7 起)的一部分。它是指向檔案/目錄的路徑抽象,而且路徑不僅可以在本機磁碟上,也可以位於例如 ZIP 封存檔內或遠端資源上(前提是有對應的 provider)。
如果說 File 是舊式紙本地圖,那麼 Path 就是 GPS 導航。
如何建立 Path 物件?
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) {
Path path1 = Paths.get("example.txt"); // 相對路徑
Path path2 = Paths.get("folder", "file.txt"); // 拼接路徑片段
System.out.println("路徑 1: " + path1.toAbsolutePath());
System.out.println("路徑 2: " + path2.toAbsolutePath());
}
}
優點:不必思考分隔符。Paths.get 會依你的作業系統選用正確格式。
在 File 與 Path 之間轉換
- File → Path: file.toPath()
- Path → File: path.toFile()
File file = new File("test.txt");
Path path = file.toPath();
Path anotherPath = Paths.get("data.txt");
File anotherFile = anotherPath.toFile();
路徑操作:resolve、relativize、normalize
路徑拼接(resolve)
Path dir = Paths.get("myfolder");
Path file = dir.resolve("notes.txt"); // myfolder/notes.txt
System.out.println(file); // myfolder/notes.txt
相對路徑(relativize)
Path pathA = Paths.get("folderA/file1.txt");
Path pathB = Paths.get("folderA/subfolder/file2.txt");
Path relative = pathA.relativize(pathB);
System.out.println(relative); // ../subfolder/file2.txt
路徑正規化(normalize)
Path messy = Paths.get("folder/../folder/file.txt");
Path clean = messy.normalize();
System.out.println(clean); // folder/file.txt
範例:構建檔案路徑
Path home = Paths.get(System.getProperty("user.home"));
Path docs = home.resolve("Documents");
Path myFile = docs.resolve("myfile.txt");
System.out.println("檔案路徑: " + myFile.toAbsolutePath());
3. 類別 Files:你的瑞士軍刀
Files 類別位於 java.nio.file 套件中——基於 Path 的檔案與目錄操作靜態工具方法集合。它幾乎無所不能:檢查存在、建立/刪除、讀/寫、複製/移動、取得屬性與遍歷目錄樹。
Files 類別的主要方法
- Files.exists(path) — 檢查檔案/目錄是否存在。
- Files.isDirectory(path) — 是否為目錄。
- Files.size(path) — 檔案大小。
- Files.createFile(path) — 建立檔案。
- Files.createDirectory(path) — 建立目錄。
- Files.delete(path) — 刪除檔案/目錄。
- Files.copy(src, dest) — 複製檔案。
- Files.move(src, dest) — 移動/重新命名。
- Files.getLastModifiedTime(path) — 最後修改時間。
- Files.readAllBytes(path) — 讀取整個檔案為位元組陣列。
- Files.readAllLines(path) — 讀取文字檔的所有行。
- Files.write(path, bytes) — 寫入位元組到檔案。
範例:檢查檔案
import java.nio.file.*;
public class FilesDemo {
public static void main(String[] args) {
Path path = Paths.get("example.txt");
System.out.println("檔案存在嗎? " + Files.exists(path));
System.out.println("這是目錄嗎? " + Files.isDirectory(path));
if (Files.exists(path)) {
try {
System.out.println("檔案大小: " + Files.size(path) + " 位元組");
} catch (Exception e) {
System.out.println("取得大小時發生錯誤: " + e.getMessage());
}
}
}
}
4. 實作:建立物件、輸出屬性
為檔案與目錄建立物件
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CompareDemo {
public static void main(String[] args) {
// 舊方法
File oldFile = new File("test.txt");
File oldDir = new File("mydir");
// 新方法
Path newFile = Paths.get("test.txt");
Path newDir = Paths.get("mydir");
System.out.println("=== File API ===");
System.out.println("檔案: " + oldFile.getAbsolutePath());
System.out.println("存在嗎? " + oldFile.exists());
System.out.println("是檔案嗎? " + oldFile.isFile());
System.out.println("是目錄嗎? " + oldDir.isDirectory());
System.out.println("\n=== Path API ===");
System.out.println("檔案: " + newFile.toAbsolutePath());
System.out.println("存在嗎? " + java.nio.file.Files.exists(newFile));
System.out.println("是檔案嗎? " + java.nio.file.Files.isRegularFile(newFile));
System.out.println("是目錄嗎? " + java.nio.file.Files.isDirectory(newDir));
}
}
輸出檔案屬性
import java.nio.file.*;
public class FileProperties {
public static void main(String[] args) {
Path path = Paths.get("test.txt");
System.out.println("絕對路徑: " + path.toAbsolutePath());
System.out.println("檔名: " + path.getFileName());
System.out.println("父目錄: " + path.getParent());
if (Files.exists(path)) {
try {
System.out.println("大小: " + Files.size(path) + " 位元組");
System.out.println("最後修改: " + Files.getLastModifiedTime(path));
} catch (Exception e) {
System.out.println("取得資訊時發生錯誤: " + e.getMessage());
}
} else {
System.out.println("找不到檔案。");
}
}
}
5. 比較:File vs Path/Files
| 功能 | File (java.io) | Path + Files (java.nio.file) |
|---|---|---|
| 路徑表現 | 僅本機磁碟 | 本機磁碟、ZIP、網路資源 |
| 路徑拼接 | 以斜線手動串接 | 方便使用 resolve |
| 存在性檢查 | exists() | Files.exists(path) |
| 讀寫內容 | 否 | 是(Files.readAll...、Files.write) |
| 取得屬性 | 基本(length()、lastModified()) | 進階屬性與視圖 |
| 相容性 | 適用所有 Java 版本 | Java 7 以上 |
| 符號連結支援 | 受限 | 完整支援 |
簡述:何時使用哪一套?
- 新專案——請使用 Path 與 Files。
- 維護舊程式碼——有時仍需與 File 搭配。
6. 實用細節
相對與絕對路徑
相對路徑:相對於目前工作目錄的路徑;絕對路徑:自檔案系統根目錄起的完整路徑。
Path relative = Paths.get("data", "file.txt");
Path absolute = relative.toAbsolutePath();
System.out.println("絕對路徑: " + absolute);
跨平台性
Path 與 Files 會考量作業系統的特性(分隔符、編碼等)。不要手動書寫像 "C:\\folder\\file.txt" 這樣的路徑——請使用 Paths.get 與 resolve。
在 File 與 Path 之間轉換
如果你有以 File 為主的舊碼,很容易切換到新 API:
File legacy = new File("legacy.txt");
Path modern = legacy.toPath();
if (Files.exists(modern)) {
// 現在即可使用 NIO.2 的所有功能
}
檢查檔案是否存在
Path path = Paths.get("notes.txt");
if (Files.exists(path)) {
System.out.println("找到檔案!");
} else {
System.out.println("檔案不存在。");
}
7. 迷你實作:建立並檢查檔案與目錄
import java.nio.file.*;
public class MiniPractice {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("demo_dir");
Path file = dir.resolve("hello.txt");
// 若目錄不存在則建立
if (!Files.exists(dir)) {
Files.createDirectory(dir);
System.out.println("已建立目錄: " + dir.toAbsolutePath());
}
// 若檔案不存在則建立
if (!Files.exists(file)) {
Files.createFile(file);
System.out.println("已建立檔案: " + file.toAbsolutePath());
}
// 輸出屬性
System.out.println("檔案存在嗎? " + Files.exists(file));
System.out.println("是檔案嗎? " + Files.isRegularFile(file));
System.out.println("大小: " + Files.size(file) + " 位元組");
// 刪除檔案與目錄(可選)
Files.delete(file);
Files.delete(dir);
System.out.println("已刪除檔案與目錄。");
}
}
8. 使用 File/Path/Files 時的常見錯誤
錯誤 1:混淆 File 與 Path。 許多新手會嘗試把 Files 的方法用在 File 物件上。記住:Files.* 適用於 Path。如果你手上是 File,先呼叫 file.toPath()。
錯誤 2:以為建立 File 或 Path 物件會建立檔案。 路徑物件是捷徑,而不是真實檔案。要建立檔案請使用 Files.createFile(path) 或進行資料寫入。
錯誤 3:以字串手動拼裝路徑。 不要寫 "folder/file.txt" 或 "folder\\file.txt"。請使用 Paths.get(...) 與 resolve(...)。這更安全且可跨平台。
錯誤 4:忽略例外。 檔案操作會丟出 IOException 等例外。請透過 try-catch 處理,或向上拋出(throws)。
錯誤 5:先用 File.exists() 檢查,接著卻用 Path 操作。 盡量維持一致風格:既然開始用 Path,就請使用 Files.exists(path) 與其他 Files 方法。
GO TO FULL VERSION