在调用openFileInput之前检查文件是否存在

Pie*_*ces 25 java android file file-exists

要从应用程序的专用存储区域读取Android中的文件,请使用该功能openFileInput().

我的问题是,有没有办法在调用此函数之前检查此文件是否存在?该函数可以抛出一个FileNotFoundException,但我觉得调用它然后基于a做一些事情try- 这catch是一个不好的做法.

使用File.exist()似乎也是一件奇怪的事情,因为它需要实例化一个类,我不确定是否只是将文件的名称传递给它将使它在我的手机的私有区域中找到该文件.

cod*_*e22 50

public boolean fileExists(Context context, String filename) {    
    File file = context.getFileStreamPath(filename);
    if(file == null || !file.exists()) {
        return false;
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

此外,这是外部存储中文件的另一种方式.

String fileUrl = "/appname/data.xml";
String file = android.os.Environment.getExternalStorageDirectory().getPath() + fileUrl;
File f = new File(file);

if(f.exists())
return;
Run Code Online (Sandbox Code Playgroud)

  • 注意:以这种方式使用 File.exists() 1) 不能防止所有异常,2) 让您容易受到竞争条件的影响,3) 使您的编程平均速度变慢......除非不存在的文件是 *可能*的情况。 (2认同)

Ste*_*n C 32

该函数可以通过FileNotFoundException,但我觉得调用它然后基于try catch做一些事情是不好的做法.

我不同意.IMO,它正在测试文件是否存在,然后打开这是不好的做法.比较这两个版本的代码:

File f = new File("someFile");
InputStream is;
Run Code Online (Sandbox Code Playgroud)

版本#1

if (f.exists()) {
    is = new FileInputStream(f);
    ...
} else {
    System.err.println("Doesn't exist");
}
Run Code Online (Sandbox Code Playgroud)

版本#2

try {
    is = new FileInputStream(f);
    ...
} catch (FileNotFoundException ex) {
    System.err.println("Doesn't exist");
}
Run Code Online (Sandbox Code Playgroud)

第一个版本存在许多问题:

  • 版本#1在您致电时进行额外的系统调用f.exists().这使得第一个版本平均较慢,除非该文件很可能不存在.

  • 版本#1具有竞争条件.如果某个外部进程大致同时删除该文件,则最终可能file.exists()返回true,然后FileInputStream构造函数抛出FileNotFoundException.如果有问题的文件是安全关键的,那么这种竞争条件可被利用来破坏安全性.(实际上,还存在第二种竞争条件,即创建文件并file.exists()在后续尝试打开它时返回false.但是这种竞争条件可能是无害的.)

另一个问题是false声明为投掷new FileInputStream.测试以查看文件是否存在仅处理可能的故障模式之一.FileInputStream无论如何,你的代码必须要抓住并处理其他的代码.


@Pieces评论道:

例外情况应该是当你无法控制的事情出现问题时.在这种情况下,我完全控制它.

实际上,您无法完全控制它.当然不是一般情况.即使在您的特定用例中,理论上仍然可能存在竞争条件.

但是,这种思路的真正问题在于,在异常/异常处理是最佳解决方案的情况下,您最终会跳过箍以避免异常.这使得代码更复杂,可读性更低,并且可能更慢和/或更脆弱.

正常的教条是这样的:

"例外情况只应在特殊情况下使用".

这和说你说的不一样."特殊"这个词实际上只是意味着"不正常".这比"你无法控制的事情确实出错"具有更广泛的意义.

我倾向于扩展教条如下:

  • 不应将例外用于正常的流量控制.

  • 如果它们的平均价格过高,则不应使用例外情况.

  • 如果用于避免它们的测试不可靠,则应使用例外.

  • 如果用于避免它们的测试平均过于昂贵,则应使用例外.

  • 如果它们显着简化了代码(以上为模),则应使用例外.简单的标准是代码是否可由普通Java程序员读取.

(注- "平均"和" 昂贵" ...)

现在人们可以争论,直到奶牛回家了解事件需要多么特殊,但我的看法是,这实际上是平衡方法(在上下文中)与平均绩效成本(在上下文中)相对简单的问题. ).在某些情况下,任何不考虑权衡和背景的教条规则都会对你造成伤害.

  • 如果文件不存在,可能是因为这是用户第一次打开应用程序,我想调用一个用默认值写入它的函数(也许我应该在我的问题中注意到).你所建议的是我会考虑通过例外编程.例外情况应该是当你无法控制的事情出现问题时.在这种情况下,我完全控制它.异常处理仍然存在,并且能够记录这些竞争条件(如果发生),这是我无法控制的情况. (2认同)