为啥 FileOutputStream 会抛出 FileNotFoundException?

Posted

技术标签:

【中文标题】为啥 FileOutputStream 会抛出 FileNotFoundException?【英文标题】:Why does FileOutputStream throw FileNotFoundException?为什么 FileOutputStream 会抛出 FileNotFoundException? 【发布时间】:2013-12-08 08:54:48 【问题描述】:

android 开发者参考 (this page) 说:

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 我应该指出,我实际上并没有得到异常,只是为它可能被抛出到另一台设备上的可能性做准备。但是文件夹权限是一个非常有效的点(尽管它不应该是根目录的问题,对吧?) 【参考方案1】:

例如,如果您尝试打开一个文件夹,或者您尝试打开的文件不存在,但您也没有创建它的权限,则可能会发生这种情况。

【讨论】:

这似乎是最有可能抛出异常的情况;谢谢你的回答 有道理,虽然异常名称的选择非常糟糕! “不存在”是正确的,但“但您也没有创建它的权限”不是。 FileOutputStream 不会尝试创建目录。【参考方案2】:

ContextImpl.openFileOutput 在 ICS 上实现如下:

@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 异常,但是您可以看到它不是线程安全,因此如果其他线程正在删除 f.getParentFile() 可能仍会抛出该异常/data/data/com.yourpkg.name/files 目录。

【讨论】:

我看到对“附加模式”的引用,这不是默认功能,但是感谢您说明可以抛出异常的情况 博达的回答真的是你说的那种情况吗? 是的,因为缺少源文件夹也可能导致问题,他的回答对于提出这个问题的其他人来说是最有可能和相关的。不过,我借此机会感谢您对答案的深入和研究 好奇创建父目录而不是祖父等目录。 Android 想要限制你所有的 'misc' 文件存储在你的包目录的 'files' 文件夹中。【参考方案3】:

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

【讨论】:

您说的是通用 Linux,对于这种特殊的 Android 'files' 文件夹案例,'files' 文件夹通常由框架 API 创建。因此,当用户故意手动创建“文件”文件夹而不分配写权限时,您的答案中提到的情况会发生吗? @Rohan 我说的是通用操作系统。我的回答中没有出现“Linux”这个词,它同样适用于 Unix、Windows、AIX、HP-UX、Solaris、MS.DOS、OS/2、IX/370 和许多其他系统。我已经解决了最终目录中的权限问题。【参考方案4】:

在我的情况下,原因是文件名不正确。 显然,不喜欢文件名中的冒号。

不工作(-> 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之间的区别是“.”而不是“:”)

【讨论】:

谢谢! “。”而不是“:”是我正在寻找的!

以上是关于为啥 FileOutputStream 会抛出 FileNotFoundException?的主要内容,如果未能解决你的问题,请参考以下文章

为啥“prepareCall”会抛出 NumberFormatException?

为啥 BluetoothSetLocalServiceInfo 会抛出错误 1314?

为啥geoip会抛出异常?

为啥这个 OdbcConnection 会抛出 System.InvalidOperationException?

为啥 jsonwebtoken 会抛出“无效签名”错误?

为啥 canvas.toDataURL() 会抛出安全异常?