为什么FileOutputStream会抛出FileNotFoundException异常?

14

Android开发者参考文献(此页面)指出:

Throws FileNotFoundException

但是,在开头的地方,它说:
打开与此上下文的应用程序包关联的私有文件进行写入。如果文件不存在,则创建该文件
如果是这样,为什么FileNotFoundException会被抛出呢?
我只想确保我正确处理了所有情况。我正在使用默认功能,所以我可以将其包装在try...catch块中,在catch块中不放置任何内容,因为在默认功能中不可能抛出FileNotFoundException吗?
编辑:'默认功能'的示例:
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

你的应用程序有可能没有权限在你指定的位置创建文件吗? - Pshemo
@Pshemo 我应该指出,我实际上并没有获得异常,只是为可能在另一台设备上抛出它做准备。但文件夹权限是一个非常有效的问题(尽管在根目录上不应该是一个问题,对吧?) - 1owk3y
4个回答

12

比如,当您尝试打开一个文件夹或者您所尝试打开的文件不存在时,就会出现这种情况;但是您既没有权限创建该文件也无法访问它。


这似乎是最有可能抛出异常的情况;感谢您的回答。 - 1owk3y
4
有道理,尽管命名异常时选择了一个非常糟糕的名称! - Rob Grant
1
“不存在”是正确的,但“但您也没有权限创建它”不是。FileOutputStream 不会尝试创建目录。 - user207421
1
有时候为什么没有权限? - pain

3

在ICS上,ContextImpl.openFileOutput的实现如下:

@Override
public FileOutputStream openFileOutput(String name, int mode)
    throws FileNotFoundException {
    final boolean append = (mode&MODE_APPEND) != 0;
    File f = makeFilename(getFilesDir(), name);
    try {
        FileOutputStream fos = new FileOutputStream(f, append);
        setFilePermissionsFromMode(f.getPath(), mode, 0);
        return fos;
    } catch (FileNotFoundException e) {
    }

    File parent = f.getParentFile();
    parent.mkdir();
    FileUtils.setPermissions(
        parent.getPath(),
        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
        -1, -1);
    FileOutputStream fos = new FileOutputStream(f, append);
    setFilePermissionsFromMode(f.getPath(), mode, 0);
    return fos;
}

makeFileName函数将确保您无法在此处指定任何目录结构:

private File makeFilename(File base, String name) {
        if (name.indexOf(File.separatorChar) < 0) {
            return new File(base, name);
        }
        throw new IllegalArgumentException(
                "File " + name + " contains a path separator");
    }

虽然看起来似乎不可能出现Fnf异常,但你可以看到它不是线程安全的,因此如果其他线程删除了/data/data/com.yourpkg.name/files目录,f.getParentFile()仍可能抛出该异常。

我看到了关于“追加模式”的引用,这不是默认功能,但是感谢您阐明了一个异常可能被抛出的情况。 - 1owk3y
博达的回答确实是你所说的那个情况吗? - Robin
是的,因为缺少源文件夹也可能导致此问题,他的答案对于任何提出这个问题的人来说都是最有可能和相关的。然而,我借此机会感谢您在回答中所付出的深度和研究量。 - 1owk3y
有趣的是它费心创建父目录,但不创建祖父等目录。 - user207421
Android希望将所有“misc”文件限制为存储在包目录中的“files”文件夹中。 - Robin

2
在我的情况下,原因是文件名不正确。显然,文件名中的冒号是不被允许的。 以下是无法工作的情况(-> FileNotFoundException):
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS");
    String fileName = simpleDateFormat.format(new Date());
    FileOutputStream fileOutputStream = new FileOutputStream(new File(context.getFilesDir(), fileName), false);

工作中:

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss.SSS");
    [...]

(SimpleDateFormat 中 HH、mm 和 ss 之间使用 "." 而不是 ":" 是它们的区别)

谢谢!我想要的是“.”而不是“:”! - Inoy

2
最常见的原因是中间目录不存在。 FileOutputStream 不会创建这些中间目录。也可能是权限问题:整个路径已经存在,但您没有在最终目录中创建权限,或者如果该文件已经存在,则没有覆盖权限。

1
你正在谈论通用的Linux,对于这个特殊的Android“files”文件夹案例,'files'文件夹通常是由框架API创建的。因此,在没有分配写入权限的情况下,当用户有意手动创建'file'文件夹时,你回答中提到的情况将会发生吗? - Robin
1
@Rohan,我在谈论通用操作系统。我的回答中没有出现“Linux”这个词,它同样适用于Unix、Windows、AIX、HP-UX、Solaris、MS.DOS、OS/2、IX/370以及其他许多系统。我已经解决了最终目录权限的问题。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接