CodeGym /課程 /JAVA 25 SELF /取得與修改檔案屬性

取得與修改檔案屬性

JAVA 25 SELF
等級 39 , 課堂 4
開放

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 屬性速覽

屬性 回傳內容
creationTime()
檔案/資料夾的建立日期與時間
lastModifiedTime()
最後修改的日期與時間
lastAccessTime()
最後存取的日期與時間
size()
檔案大小(位元組)
isDirectory()
是否為目錄?
isRegularFile()
是否為一般檔案?
isSymbolicLink()
是否為符號連結?

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! 這些方法可能拋出 UnsupportedOperationExceptionIOException
  • 權限不一定只有「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)

1
問卷/小測驗
與檔案系統打交道,等級 39,課堂 4
未開放
與檔案系統打交道
與檔案系統打交道
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION