首页 > 图灵资讯 > 技术篇>正文

要记住的边缘情况零件文件

2024-08-14 11:11:10

要记住的边缘情况零件文件

你知道吗,可能同时存在或不存在一个文件吗?你知道,你可以删除文件并仍然使用它吗?在软件开发中发现这些和其他文件的边缘。

在我之前关于软件开发边缘的文章中,我写了一篇关于文本陷阱的文章,并给了你一些建议,以及如何避免它们。在这篇博客文章中,我想关注文件和文件 i/o 操作。

不是文件的文件

java.io.file api 提供了以下 3 种方法:

  • #exists()

  • #isdirectory()

  • #isfile()

人们可能会认为,如果它指向存在的给定路径,对象要么是文件,要么是目录 - 就像 stack overflow 这个问题是一样的。然而,这并不总是正确的。

file#isfile() javadocs 文件中没有明确提及,但文件中没有明确提及 **确实意味着 **常规文件。因此,特殊的 unix 可能存在文件(如设备、套接字和管道),但它们不是定义中的文件。

看下面的片段:

import java.io.file

val file = file("/dev/null")
println("exists:      ${file.exists()}")
println("isfile:      ${file.isfile()}")
println("isdirectory: ${file.isdirectory()}")

就像你在现场演示中看到的,可能既不是文件也不是目录。 file。

存在还是不存在?

符号链接也是一个特殊的文件,但在(旧)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())
    }
}
</assetfiledescriptor>

如果你使用它,请注意#apply(),这个值不会持续很长时间——所以你不会得到任何异常。但是,持有这个值 sharedpreferences 在实例应用程序终止之前,它将能够访问。这是因为共享偏好也保存在内存中。

亡灵确实存在

人们可能认为僵尸、食尸鬼和其他类似的生物只存在于幻想和恐怖小说中。但它们在计算机科学中是真实的!这些常见术语指的是僵尸过程。事实上,死亡文件也可以很容易地创建。

在类unix操作系统中,文件删除通常是通过取消链接来实现的。未链接的文件名称将从文件系统中删除(假设它是最后一个硬链接),但任何打开的文件描述符仍然有效和可用。您仍然可以阅读和写入此类文件。这是一个片段:

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?: ${file.delete()}")
   println("content?: ${it.readLine()}")
}

还有现场演示。

包起来

首先,请记住,在创建不存在的目录时,我们不能忘记正确的调用顺序。此外,请记住,同时打开的文件数量是有限的,而不仅仅是计算您打开的文件很清楚。最后但并非最不重要的是,在最后一次使用之前删除文件的技巧可以为您提供更多的灵活性。

最初于2017年9月27日发布的wwwww.thedroidsonroids.com。

以上是要记住的边缘情况零件文件的详细内容,请关注图灵教育的其他相关文章!

上一篇 java框架如何通过函数式编程提高代码可读性和维护性?
下一篇 返回列表

文章素材均来源于网络,如有侵权,请联系管理员删除。