为什么有时会抛出FileNotFoundException

时间:2015-11-30 14:25:00

标签: android filenotfoundexception fileoutputstream

代码大部分时间都有效,但有时会引发异常。无法弄清楚可能导致它的原因。

创建文件是做什么的
  

/storage/emulated/0/Download/theFileName.jpg

并向其写入数据(来自sourceFile,确实存在),但得到的文件不存在"新创建的文件的例外。

(在清单中确实有uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE", and uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"。

File sourceFile = new File(theSourceFileFullPath);
if (sourceFile.exists()) {
    File downloadDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    String downloadPath = downloadDirectory.getPath();
    String newFilePath = (downloadPath + "/" + fileName);
    File newFile = new File(newFilePath);
    try {
        FileInputStream in = new FileInputStream(sourceFile);

        // ava.io.FileNotFoundException: 
        //     /storage/emulated/0/Download/theFileName.jpg: open failed: ENOENT (No such file or directory) 
        // exception at this line       
        FileOutputStream out = new FileOutputStream(newFile);
        //......
     } catch (Exception e) {}
}

6 个答案:

答案 0 :(得分:7)

我可以想到以下可能的原因:

  1. 无法创建新文件只是因为SD卡上没有可用空间。下次遇到此问题时,请尝试通过文件管理器或“设置”查看您是否至少有一些可用空间 - >存储。如果这是用户设备上发生的事情,我怀疑你可以做些什么。
  2. 由于某些操作系统故障或物理上未连接,SD卡无法使用,因此无法创建文件。再一次 - 除了向某些Toast显示错误消息之外,您无能为力。
  3. 如何生成文件路径的fileName部分? Sometimes无法创建文件,因为文件名包含不受支持的(通过此特定设备)字符。例如。我有Android 4.1.2的HTC Desire X,如果文件名包含冒号,则无法使用类似于你的代码创建文件。尝试另一种方法来生成文件名,看看它是否有所作为。
  4. 在创建文件之前,您确定Downloads目录是否存在?写下如下内容:

    if (!downloadDirectory.exists()) {
        downloadDirectory.mkdirs();
    }
    
  5. 在Android 6上WRITE_EXTERNAL_STORAGE权限被视为dangerous,因此用户可以随时撤消该权限。 Make sure用户在写入文件之前未撤消此权限。
  6. 完成工作后,
  7. Always close the I/O stream。将finally子句添加到try-catch块并关闭其中的inout个流:

    finally {
        if (in != null) {
            try {
                in.close();
            } catch (Exception e) { }
        }
    
        if (out != null) {
            try {
                out.close();
            } catch (Exception e) { }
        }
    }
    
  8. 最后一个 - 最后我没有选择。 :)我想如果你从多个线程写入相同的文件,也会出现这个问题。如果是这种情况,请尝试同步对文件编写代码的访问。

答案 1 :(得分:2)

根据Java文档 - Class FileNotFoundException

  

public class FileNotFoundException extends IOException

     

表示尝试打开由指定路径名表示的文件失败。

     

FileInputStream将抛出此异常,   当文件包含时,FileOutputStreamRandomAccessFile构造函数   指定的pathname不存在。它也会被这些抛出   构造函数如果文件存在但由于某种原因是   无法访问,例如尝试打开只读时   写作文件。

要恢复,有三种情况可能会抛出FileNotFoundException

  1. 指定的文件不存在。
  2. 指定的文件实际上是一个目录。
  3. 由于某种原因,无法打开指定的文件进行阅读。
  4.   

    得到"文件不存在"新创建的文件的例外。

    在您的代码中,我没有看到两件事

    1. 成功写入后删除文件。我一点也不开玩笑。如果我有这样的类和那个错误,我会做一种测试,在从源文件复制内容后删除downlaodDirectory完成。在这种情况下,它会传递方法,或者你会得到另一个,但更具体的错误 - 就像在我的话:无法删除文件。在使用它
    2. 写入数据后关闭文件。我也没有看到关闭文件的方法。在您的代码中,似乎您的文件仍处于打开状态,因此您再次运行应用程序,并且您会因错误而无法预料。
    3. 要解决此问题,请在使用file.close()方法处理数据后关闭这两个文件。

      希望有所帮助

答案 2 :(得分:1)

  1. 由于您创建文件的方式,可能会发生此问题:

    String downloadPath = downloadDirectory.getPath();
    String newFilePath = (downloadPath + "/" + fileName);
    File newFile = new File(newFilePath);
    

    危险代码在这里:

    String newFilePath = (downloadPath + "/" + fileName);
    

    相反,请尝试使用以下方法:

    File newFile = new File(downloadDirectory, fileName);
    
  2. SD卡可用性 - 请查看以下文档 http://developer.android.com/training/basics/data-storage/files.html#WriteExternalStorage。 可能是未安装媒体(例如在某些旧设备上) 当用户通过usb将设备连接到计算机时会发生这种情况。所以,尝试一下 检查媒体是否安装:

    /* Checks if external storage is available for read and write */
    public boolean isExternalStorageWritable() {
         String state = Environment.getExternalStorageState();
         if (Environment.MEDIA_MOUNTED.equals(state)) {
             return true;
         }
         return false;
     }
    

    如果没有通知用户。

答案 3 :(得分:0)

我希望你的代码在文件中写入数据是完美的我只是专注于你的问题。我认为有两种可能性让文件找不到例外。

  1. 有些时候文件名不支持某些特殊字符当你提供这种字符时,文件名不正确生成了这就是为什么会出现这个错误所以请确保你的文件名是正确的。
  2. second是你的文件扩展名。你没有指明你有哪种文件。
  3. 这里我有一些代码片段我希望这能帮助你解决问题。

    <强>解决方案

       File file=new File(Environment.getExternalStorageDirectory()+"/"+ConstansClass.FOLDERNAME);
        if(!file.exists())
        {
            file.mkdir();
        }
    
    
        String file=filename.replaceAll("[^a-zA-Z0-9.-]", " ");
        yourDir = new File(file, file+".mp3");
        if(yourDir.exists())
        {
            return yourDir;
        }
    

    修改

    我很抱歉lannf我不知道你的代码究竟发生了什么,但我有一个代码片段,它只是从soundcloude下载mp3文件并存储在我的本地storage.i认为它与你的需求完全相同。所以我发布了我的代码。

     @Override
    protected File doInBackground(Void... params) {
    
    
        //File sdCardRoot = Environment.getExternalStorageDirectory()+"/Music";
    
        File file=new File(Environment.getExternalStorageDirectory()+"/"+ConstansClass.FOLDERNAME);
        if(!file.exists())
        {
            file.mkdir();
        }
    
    
        String filename=soundCloudeResponse.getTitle();//.replaceAll("[^a-zA-Z0-9.-]", " ");
        yourDir = new File(file, filename+".mp3");
        if(yourDir.exists())
        {
            return yourDir;
        }
        String url=soundCloudeResponse.getStream_url()+"?"+ConstansClass.SOUNDCLOUDE_CLIENT_ID;
    
        URL u = null;
        try {
            DebugLog.e("Request Url"+ url);
            u = new URL(url);
            URLConnection conn = u.openConnection();
            int contentLength = conn.getContentLength();
    
            DataInputStream stream = new DataInputStream(u.openStream());
    
            byte[] buffer = new byte[contentLength];
            stream.readFully(buffer);
            stream.close();
    
            DataOutputStream fos = new DataOutputStream(new FileOutputStream(yourDir));
            fos.write(buffer);
            fos.flush();
            fos.close();
            DebugLog.d("Download Complete in On Background");
    
    
        } catch (MalformedURLException e) {
            sucess=false;
            e.printStackTrace();
    
        } catch (IOException e) {
            sucess=false;
            e.printStackTrace();
    
        }
        catch (Exception e)
        {
            sucess=false;
            e.printStackTrace();
            DebugLog.e("Error ::"+e.getMessage());
        }
    
    
        return yourDir;
    }
    

    我认为您是智能开发人员,因此您可以根据自己的要求修改此代码。

    最好的运气

答案 4 :(得分:0)

你没有发布完整的异常堆栈跟踪,但我发现确切的问题已经解决了。

java.io.FileNotFoundException: /storage/emulated/0/bimagechooser/1429031333305.jpg: open failed: ENOENT (No such file or directory)

使用此库image-chooser-library.&amp;需要重新计算代码。

The Guy coomar2841。一定会帮到你。因为他花了几个小时来解决问题。所以节省你的时间。

  

获取com.kbeanie.imagechooser的来源并将其放入您的APP,删除了库的gradle声明,APP应该可以正常工作。

请查看 GitHub Issue

我希望它对你有用。 :)

答案 5 :(得分:0)

可能还有另外一种可能性:

如果代码的一部分正在写入文件,而另一部分正在读取文件,那么最好在写入者完成写入文件之前考虑读者正在读取文件。

您可以通过将代码置于调试模式来交叉检查这种情况。如果在该处工作正常,并给您FileNotFoundException,那么肯定是造成此异常的潜在原因。

现在,如何解决:

您可以使用类似于以下代码块的重试机制

if(!file..exists()){
Thread.sleep(200);}

在您的代码中,并根据需要更改睡眠值。

希望有帮助!!