簡體   English   中英

如何在 Java 中創建一個 isReadable(path) 返回 false 的路徑?

[英]How to make create a path in Java for which isReadable(path) returns false?

此論壇中的其他問題詢問如何使 Java 中的文件不可讀。 這個問題不一樣。 我發現的其他問題指出了如何鎖定文件不被讀取,但Files.isReadable(Path)仍然返回true

在 Windows 10 上使用 Java 17 我有一個方法,如果Files.isReadable()對某個路徑返回false ,則該方法有合同要做(或不做)某些事情。 我需要測試那個方法,所以我需要人為地創建一個Files.isReadable()返回 false 的文件或目錄(最好是每個目錄中的一個)。

我嘗試在文件上創建排他鎖:

Path lockedFile = writeString(directory.resolve("locked.txt"), "locked");
try (final FileChannel channel = FileChannel.open(lockedFile, StandardOpenOption.APPEND);
    FileLock lock = channel.lock()) {
  System.out.println("is locked file readable? " + isReadable(lockedFile));
}

然而isReadable()仍然返回true

我試過使用File.setReadable()

Path lockedFile = writeString(directory.resolve("locked.txt"), "locked");
lockedFile.toFile().setReadable(false);
System.out.println("is locked file readable? " + isReadable(lockedFile));

仍然Files.isReadable()返回true

我可以對文件做什么以使isReadable()返回false (某些特定於 Windows 的東西是可以接受的,因為我可以將我的單元測試設置為僅在 Windows 上運行,但至少我能夠測試該方法。)

可以說,“涵蓋該領域”的解決方案是在測試任何與任何類型的文件系統相關的任何文件系統時,就是編寫自己的文件系統 好的。 取出蚊子可能有點像火箭筒,但是,這個原則幾乎可以擴展到您想要做的所有事情並使用文件系統進行測試。

例如,想要一些寫出文件的代碼,並且想要檢查它是否確實寫入了正確的數據? 您可以只創建該文件,但現在您確實需要擔心在測試期間要寫入的一些目錄。 文件系統訪問也很慢,這也意味着您需要擔心測試后的清理工作。 為了可並行化的目的,也很難將它們隔離開來。 所有這些東西充其量只是輕微的煩惱,但它開始感覺像是被千刀萬剮的死亡。

您正在做的另一個主要缺點是文件系統本質上在架構/操作系統之間存在很大差異。 例如,您可以使用AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class); view.setAcl(Collections.emptyList()); AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class); view.setAcl(Collections.emptyList()); 如果您使用的操作系統支持在支持基於 acl 的訪問系統概念的文件系統上設置文件,這可能會導致.isReadable返回 false。

這會導致相當糟糕的結果,即您的代碼每次都可以在您的硬件上完美運行,但您在不同平台上工作的伙伴卻無法使用該代碼。 如果您不想這樣,虛擬文件系統可以為您解決這個問題。

寫我自己的..什么?

One of the advantages of the 'new' file IO stuff ( java.nio.file , vs. the old java.io stuff) is that filesystems are mostly abstracted out.

“文件系統”的概念是您可以定義的。 因此,您可以定義一個完全在 memory 中運行的程序——您現在不再需要擔心清理,它會盡可能快,並且如果您希望它們獨立於任何其他測試,它將獨立於任何其他測試。 它還使 mocking 的內容(“嘲笑”,英文單詞,而不是“嘲笑”,例如 JMock)變得容易得多。

有點像時間的東西,您必須始終使用正確的調用(即,如果您習慣在源代碼中調用LocalDate.now() ,則需要將其切換到LocalDate.now(clock)以便您可以設置虛擬時鍾進行穩定測試)。 您不能在任何地方都使用Paths.get() - Path object “編碼”哪個文件系統正在使用(並且您希望它“編碼”您的測試文件系統正在使用)。

而不是Paths.get("/path/stuff")您必須調用:

someFileSystem.getPath("/path/stuff")其中someFileSystem可以是FileSystems.getDefault() ,然后它會得到與Paths.get相同的行為,但它需要注入,以便在測試條件下,你可以讓它成為你的測試文件系統。

現在你所需要的只是一個假文件系統。 不幸的是,文件系統 API 相當復雜。 自己做並不是一件容易的事。 幸運的是,你不必給這只氂牛剃毛。 某人(具體來說是 Google 的開發團隊)已經為您完成了這項工作。 介紹JimFS

缺點

  • 集成 JimFS 仍然有點復雜。
  • Paths.get("/x/y")需要放在你的 linter 的禁止列表中; 消除這一點可能需要相當多的重寫。 特別是如果您不使用依賴注入框架。 設置一個可以要求文件系統的簡單 singleton 是值得的; 在基礎上,它可以返回FileSystems.getDefault()然后所有代碼都以相同的方式工作。 然后,您可以擴展它,例如添加一個全局“用我的虛擬文件系統覆蓋”選項,或者使用ThreadLocal允許各個線程各自擁有自己的線程,無論您需要什么。
  • 舊的 API ( java.io ) 的任何使用,特別是包括嘗試使用path.toFile()都不起作用。 據我所知,舊的 API 只能與實際文件系統交互。 因此,您還需要 go 搜索代碼庫中任何舊jiFile的任何用法,並將其替換為基於fileSystem.getPath的代碼。

如果與您當前的解決方案 mocking 從jnfFiles class 相比,這感覺像是一條更艱巨的道路,這是可以理解的。 你最清楚,這是你的項目。 但是,我認為這涵蓋了您的 2 個主要選項:模擬所有內容,或者使用測試文件系統。

這在 Windows 10 中對我有用:

AclFileAttributeView view =
    Files.getFileAttributeView(path, AclFileAttributeView.class);
view.setAcl(Collections.emptyList());

為了跨操作系統的完整性,您可以通過適當的檢查來保護它,並為(大多數)Unix 文件系統添加類似的東西:

FileStore store = Files.getFileStore(path);
if (store.supportsFileAttributeView(AclFileAttributeView.class)) {
    AclFileAttributeView view =
        Files.getFileAttributeView(path, AclFileAttributeView.class);
    view.setAcl(Collections.emptyList());
} else if (store.supportsFileAttributeView(PosixFileAttributeView.class)) {
    Files.setPosixFilePermissions(path,
        EnumSet.noneOf(PosixFilePermission.class));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM