1. 讀取基本屬性:BasicFileAttributes
當我們談到檔案或資料夾時,並不只是指它的名稱或大小。每個檔案都有一份「身分證」—一組屬性,包含:
- 建立時間
- 最後修改時間
- 最後存取時間
- 大小
- 存取權限(誰可以讀、寫、執行)
- 擁有者資訊(在 Unix)
- 「隱藏」「唯讀」等標誌
在 Java 中,這些屬性可透過套件 java.nio.file.attribute 的便利且強大的 API 來操作。無需撰寫平台相依的程式碼:標準程式庫中已包含所需的一切。
先來匯入需要的類別:
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;
如何取得檔案的基本屬性?
使用方法 Files.readAttributes:
Path path = Paths.get("example.txt");
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("建立時間: " + attrs.creationTime());
System.out.println("最後修改: " + attrs.lastModifiedTime());
System.out.println("最後存取: " + attrs.lastAccessTime());
System.out.println("大小: " + attrs.size());
System.out.println("是否為目錄? " + attrs.isDirectory());
System.out.println("是否為一般檔案? " + attrs.isRegularFile());
System.out.println("是否為符號連結? " + attrs.isSymbolicLink());
} catch (IOException e) {
System.out.println("讀取屬性時發生錯誤: " + e.getMessage());
}
想像你是稽查員去檢查一間公寓。你不只看是否有門(檔案是否存在),還會詢問住戶:「房子何時建造?最後一次整修是什麼時候?誰是屋主?」
BasicFileAttributes 屬性速覽
| 屬性 | 回傳內容 |
|---|---|
|
檔案/資料夾的建立日期與時間 |
|
最後修改的日期與時間 |
|
最後存取的日期與時間 |
|
檔案大小(位元組) |
|
是否為目錄? |
|
是否為一般檔案? |
|
是否為符號連結? |
2. 進階屬性:POSIX 與 DOS
POSIX 屬性(Linux、macOS 與其他類 Unix 作業系統)
在 Unix 系統上,可以取得更進一步的資訊:權限、擁有者、群組。
try {
PosixFileAttributes posixAttrs = Files.readAttributes(path, PosixFileAttributes.class);
System.out.println("擁有者: " + posixAttrs.owner().getName());
System.out.println("群組: " + posixAttrs.group().getName());
System.out.println("權限: " + PosixFilePermissions.toString(posixAttrs.permissions()));
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援 POSIX 屬性。");
} catch (IOException e) {
System.out.println("讀取 POSIX 屬性時發生錯誤: " + e.getMessage());
}
注意: 在 Windows 上,此程式碼會拋出 UnsupportedOperationException — 這是正常的。
DOS 屬性(Windows)
在 Windows 上可以處理「唯讀」、「隱藏」、「封存」、「系統」等標誌:
try {
DosFileAttributes dosAttrs = Files.readAttributes(path, DosFileAttributes.class);
System.out.println("隱藏: " + dosAttrs.isHidden());
System.out.println("唯讀: " + dosAttrs.isReadOnly());
System.out.println("系統: " + dosAttrs.isSystem());
System.out.println("封存: " + dosAttrs.isArchive());
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援 DOS 屬性。");
} catch (IOException e) {
System.out.println("讀取 DOS 屬性時發生錯誤: " + e.getMessage());
}
3. 修改檔案屬性
閱讀別人的護照是一回事,而要去更改出生日期或姓氏又是另一回事!在 Java 中,我們可以修改檔案的屬性(前提是擁有相應權限)。
變更最後修改時間
import java.nio.file.attribute.FileTime;
Path file = Paths.get("example.txt");
try {
FileTime newTime = FileTime.fromMillis(System.currentTimeMillis() - 24 * 60 * 60 * 1000); // 減去 1 天
Files.setLastModifiedTime(file, newTime);
System.out.println("最後修改時間已變更!");
} catch (IOException e) {
System.out.println("變更時間時發生錯誤: " + e.getMessage());
}
變更權限(POSIX)
僅限 Unix 系統!例如,讓檔案對所有人可執行:
try {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-xr-x");
Files.setPosixFilePermissions(file, perms);
System.out.println("權限已變更!");
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援 POSIX 權限。");
} catch (IOException e) {
System.out.println("變更權限時發生錯誤: " + e.getMessage());
}
關於字串 "rwxr-xr-x":
- r — read(讀取)
- w — write(寫入)
- x — execute(執行)
- 第一組 3 個字元代表擁有者,第二組代表群組,第三組代表其他人。
變更隱藏/唯讀狀態(DOS 屬性,Windows)
將檔案設為隱藏:
try {
Files.setAttribute(file, "dos:hidden", true);
System.out.println("檔案已設為隱藏(Windows)!");
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援 DOS 屬性。");
} catch (IOException e) {
System.out.println("變更屬性時發生錯誤: " + e.getMessage());
}
將檔案設為「唯讀」:
try {
Files.setAttribute(file, "dos:readonly", true);
System.out.println("檔案現在為唯讀(Windows)!");
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援 DOS 屬性。");
} catch (IOException e) {
System.out.println("變更屬性時發生錯誤: " + e.getMessage());
}
4. 檢查存取權限
有時需要快速檢查檔案是否可讀、可寫或可執行:
Path file = Paths.get("example.txt");
System.out.println("可讀: " + Files.isReadable(file));
System.out.println("可寫: " + Files.isWritable(file));
System.out.println("可執行: " + Files.isExecutable(file));
這在所有平台上皆可運作,雖然實際行為取決於作業系統與安全性設定。
5. 實作:輸出檔案詳細資訊
寫一個小程式,根據檔案路徑顯示盡可能多的資訊,並嘗試修改部分屬性。
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Set;
import java.io.IOException;
public class FileAttributesDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("example.txt");
if (!Files.exists(path)) {
System.out.println("找不到檔案!");
return;
}
// 基本屬性
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("名稱: " + path.getFileName());
System.out.println("路徑: " + path.toAbsolutePath());
System.out.println("大小: " + attrs.size() + " 位元組");
System.out.println("建立時間: " + attrs.creationTime());
System.out.println("最後修改: " + attrs.lastModifiedTime());
System.out.println("最後存取: " + attrs.lastAccessTime());
System.out.println("是否為目錄? " + attrs.isDirectory());
System.out.println("是否為一般檔案? " + attrs.isRegularFile());
// 檢查存取權限
System.out.println("可讀: " + Files.isReadable(path));
System.out.println("可寫: " + Files.isWritable(path));
System.out.println("可執行: " + Files.isExecutable(path));
// 嘗試更新修改時間
FileTime now = FileTime.fromMillis(System.currentTimeMillis());
Files.setLastModifiedTime(path, now);
System.out.println("最後修改時間已更新!");
// 嘗試將檔案設為隱藏(若支援)
try {
Files.setAttribute(path, "dos:hidden", true);
System.out.println("檔案已設為隱藏(若作業系統支援)。");
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援隱藏檔案屬性。");
}
// 嘗試輸出 POSIX 權限(若支援)
try {
PosixFileAttributes posixAttrs = Files.readAttributes(path, PosixFileAttributes.class);
System.out.println("擁有者: " + posixAttrs.owner().getName());
System.out.println("權限: " + PosixFilePermissions.toString(posixAttrs.permissions()));
} catch (UnsupportedOperationException e) {
System.out.println("此作業系統不支援 POSIX 屬性。");
}
}
}
6. 實用細節
跨平台差異與建議
- 不是所有作業系統都支援所有屬性! 在 Windows 沒有 POSIX 權限,而在 Linux 沒有 DOS 屬性。
- 務必使用 try-catch! 這些方法可能拋出 UnsupportedOperationException 或 IOException。
- 權限不一定只有「rwx」! 在 Windows 權限模型不同,「唯讀」可能由作業系統的安全性政策決定。
- 「隱藏檔」是相對概念。 在 Unix 中,檔名以點開頭(.hidden)即為隱藏;在 Windows 中,需設定屬性 dos:hidden。
表格:各平台可用的屬性
| 屬性 | Windows (dos:*) | Linux/macOS (posix:*) |
|---|---|---|
| 建立時間 | + | + |
| 最後修改時間 | + | + |
| 最後存取時間 | + | + |
| 隱藏檔 | + | 僅限以點開頭的檔名 |
| 唯讀 | + | + |
| 權限(rwx) | - | + |
| 擁有者、群組 | - | + |
| 封存、系統 | + | - |
7. 操作檔案屬性時的常見錯誤
錯誤一:在 Windows 嘗試讀取或修改 POSIX 屬性。 在 Windows 上會得到 UnsupportedOperationException。撰寫跨平台程式碼時,務必處理此例外。
錯誤二:在檔案被其他行程開啟時修改其修改時間。 在某些系統中檔案可能被鎖定,操作會以錯誤結束。
錯誤三:以為「隱藏檔案」在所有作業系統上都一樣。 在 Unix 中,檔名以點開頭(.gitignore)即為隱藏;在 Windows 中,必須設定屬性 dos:hidden。不要混淆這兩種做法。
錯誤四:在操作前忽略檢查檔案是否存在。 若檔案不存在,在嘗試取得或修改屬性時會拋出 NoSuchFileException。
錯誤五:未檢查存取權限。 若使用者沒有修改屬性的權限,操作會以錯誤結束。修改前請檢查 Files.isWritable(path)。
GO TO FULL VERSION