首頁 > Java > java教程 > 主體

要記住的邊緣情況。零件文件

PHPz
發布: 2024-08-09 07:05:22
原創
391 人瀏覽過

Edge Cases to Keep in Mind. Part  Files

你知道嗎,可能有一個檔案同時存在和不存在?您是否知道,您可以刪除文件並仍然使用它?發現軟體開發中的這些和其他文件邊緣情況。

在我之前關於軟體開發中的邊緣情況的文章中,我寫了有關文字陷阱的文章,並給了您一些建議,以及如何避免它們。在這篇文章中,我想重點討論文件和文件 I/O 操作。

一個不是文件的文件

java.io.File API 提供以下 3 種方法:

  • #exists()

  • #isDirectory()

  • #isFile()

人們可能會認為,如果它由存在的給定路徑指向,則物件要么是文件,要么是目錄 - 就像 Stack Overflow 上的這個問題一樣。然而,這並不總是正確的。

File#isFile() javadocs 中沒有明確提及,但 文件 **there 確實意味著 **常規文件。因此,特殊的 Unix 檔案(如裝置、套接字和管道)可能存在,但它們不是該定義中的檔案

看下面的程式碼片段:

import java.io.File

val file = File("/dev/null")
println("exists:      ${file.exists()}")
println("isFile:      ${file.isFile()}")
println("isDirectory: ${file.isDirectory()}")
登入後複製

正如您在現場演示中看到的,可能存在既不是文件也不是目錄的文件。

存在,還是不存在?

符號連結也是特殊文件,但在(舊)java.io API 中幾乎所有地方都以透明方式處理它們。唯一的例外是 #getCanonicalPath()/#getCanonicalFile() 方法系列。這裡的透明意味著所有操作都轉發到目標,就像直接在目標上執行一樣。這種透明度通常很有用,例如您可以只讀取或寫入某個檔案。您不關心可選的連結路徑解析度。然而,這也可能會導致一些奇怪的情況。例如,可能有一個文件同時存在和不存在。

讓我們考慮一個懸掛的符號連結。它的目標不存在,因此上一節中的所有方法都會傳回 false。儘管如此,來源檔案路徑仍然被佔用,例如您無法在該路徑上建立新檔案。這是示範此案例的程式碼:

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

val path = Paths.get("foo")
Files.createSymbolicLink(path, path)
println("exists       : ${path.toFile().exists()}")
println("isFile       : ${path.toFile().isFile()}")
println("isDirectory  : ${path.toFile().isDirectory()}")
println("createNewFile: ${path.toFile().createNewFile()}")
登入後複製

還有現場示範。

順序很重要

在java.io API 中,要建立一個可能不存在的目錄並確保它之後存在,可以使用File#mkdir() (如果要建立不存在的父目錄,則可以使用File#mkdirs() 作為好)然後是File#isDirectory()。按上述順序使用這些方法非常重要。讓我們看看如果順序顛倒會發生什麼。需要兩個(或更多)執行緒執行相同的操作來示範這種情況。在這裡,我們將使用藍色和紅色的線。

  1. (紅色)isDirectory()? — 不,需要建立

  2. (藍色)isDirectory()? — 不,需要建立

  3. (紅色)mkdir()? — 成功

  4. (藍色)mkdir()? — 失敗

如您所見,藍色執行緒無法建立目錄。但它確實是被創造出來的,所以結果應該是正面的。如果 isDirectory() 在最後調用,結果總是正確的。

隱藏的限制

給定 UNIX 程序同時開啟的檔案數量限制為 RLIMIT_NOFILE 的值。在Android 上,這通常是1024,但實際上(不包括框架使用的檔案描述符)您可以使用更少(在Android 8.0.0 上使用空Activity 進行測試期間,大約有970 個檔案描述符可供使用)。如果您嘗試打開更多會發生什麼?好吧,文件不會被開啟。根據上下文,您可能會遇到具有明確原因的異常(打開文件太多),一點點神秘的消息(例如此文件無法作為文件描述符打開;它可能被壓縮)或當你通常期望true 時只是false 作為回傳值。請參閱示範這些問題的程式碼:

package pl.droidsonroids.edgetest

import android.content.res.AssetFileDescriptor
import android.support.test.InstrumentationRegistry
import org.junit.Assert
import org.junit.Test

class TooManyOpenFilesTest {
    //asset named "test" required
    @Test
    fun tooManyOpenFilesDemo() {
        val context = InstrumentationRegistry.getContext()
        val assets = context.assets
        val descriptors = mutableListOf<AssetFileDescriptor>()
        try {
            for (i in 0..1024) {
                descriptors.add(assets.openFd("test"))
            }
        } catch (e: Exception) {
            e.printStackTrace() //java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
        }
        try {
            context.openFileOutput("test", 0)
        } catch (e: Exception) {
            e.printStackTrace() //java.io.FileNotFoundException: /data/user/0/pl.droidsonroids.edgetest/files/test (Too many open files)
        }

        val sharedPreferences = context.getSharedPreferences("test", 0)
        Assert.assertTrue(sharedPreferences.edit().putBoolean("test", true).commit())
    }
}
登入後複製

請注意,如果你使用#apply(),該值將不會被持久保存-所以你不會得到任何異常。但是,在持有該 SharedPreferences 實例的應用程式程序被終止之前,它將可以存取。這是因為共享偏好也保存在記憶體中。

亡靈確實存在

人們可能認為殭屍、食屍鬼和其他類似的生物只存在於奇幻和恐怖小說中。但是……它們在電腦科學中是真實存在的!這些常見術語指的是殭屍行程。其實不死文件也可以輕鬆製作。

In Unix-like operating systems, file deletion is usually implemented by unlinking. The unlinked file name is removed from the file system (assuming that it is the last hardlink) but any already open file descriptors remain valid and usable. You can still read from and write to such a file. Here is the snippet:

import java.io.BufferedReader
import java.io.File
import java.io.FileReader

val file = File("test")
file.writeText("this is file content")

BufferedReader(FileReader(file)).use {
   println("deleted?: ${file.delete()}")
   println("content?: ${it.readLine()}")
}
登入後複製

And a live demo.

Wrap up

First of all, remember that we can’t forget about the proper method calling order when creating non-existent directories. Furthermore, keep in mind that a number of files open at the same time is limited and not only files explicitly opened by you are counted. And the last, but not least, a trick with file deletion before the last usage can give you a little bit more flexibility.

Originally published at www.thedroidsonroids.com on September 27, 2017.

以上是要記住的邊緣情況。零件文件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!