2015-11-30 108 views
16

该代码在大多数情况下都能正常工作,但有时会抛出异常。无法弄清楚是什么原因造成的。为什么有时会抛出FileNotFoundException

什么是确实是在

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

创建文件和写入数据到它(从它的资源文件确实存在),但新创建的文件得到“文件不存在”异常。

(它确实在明显有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) {} 
} 
+1

也许没有完成它的创建,你尝试访问它。每次应用程序打开时,它都会尝试创建一个文件并从中读取它? –

+0

尝试替换:File newFile = new File(downlaodDirectory,fileName); – phongvan

+0

Lispas,该应用程序已运行。 mdtuyen,File newFile = new File(downlaodDirectory,fileName);没有帮助,并且如果同时具有downlaodDirectory和fileName,它与新文件(downlaodDirectory.getPath()+“/”+ fileName)相同; – lannyf

回答

7

我能想到的这种行为如下可能的原因:

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

    if (!downloadDirectory.exists()) { 
        downloadDirectory.mkdirs(); 
    } 
    
  5. WRITE_EXTERNAL_STORAGE许可被视为dangerous对Android 6,因此可以在任何时间,用户可以撤销。 Make sure用户在写入文件之前未取消该权限。
  6. 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) { } 
        } 
    } 
    
  7. 最后一个 - 最后我出的选项。 :)我想这个问题也可能出现,如果你从多个线程写入相同的文件。如果是这种情况,请尝试同步对文件写入代码的访问。
+0

感谢aga!崩溃报告来自crashlytics,并且实例显示该设备似乎不缺乏记忆。这可能是一个小故障,但有数百个报告。文件名很简单,只要一个字。它不喜欢系统下载目录不在那里,如果它是那么同一个用户将有多个实例报告,但事实并非如此。用户可以撤销write_external_storage,但是实例分发从所有不同的设备交叉。再次感谢您列出可能的情况。 – lannyf

+0

@lannyf我忘记了另一个机会:当你完成与他们一起工作时,你没有关闭'in'和'out'流。也试试这个。 – aga

+0

谢谢你。它确实在流上关闭,但没有显示在代码片段中。 – lannyf

2

根据Java文档 - Class FileNotFoundException:当试图打开指定路径名表示的文件失败

public class FileNotFoundException extends IOException

信号。

此异常将由FileInputStream被抛出, FileOutputStream,当与 文件指定pathname不存在RandomAccessFile构造。如果文件确实存在,但是由于某种原因, 将无法​​访问,例如当试图打开只读 文件进行写入时,它也会由这些构造函数抛出。

要恢复,有三种情况可能会引发FileNotFoundException

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

新创建的文件得到“文件不存在”异常。

在你的代码,我没有看到两件事情

  1. 成功写入后删除文件。我根本不是在开玩笑。如果我有这样一个类和那个错误的类,我会做一种测试,从源文件复制内容后删除downlaodDirectory。在这种情况下,它会通过该方法,或者你会得到另一个,但更具体的错误 - 就像我的话:无法删除文件。正在使用它
  2. 写入数据后关闭文件。我也没有看到关闭文件的方法。在你的代码中,似乎是你的文件仍然是打开的,所以你再次运行一个应用程序,你得到这个不可预知的错误。

要解决该问题,只需在使用file.close()方法处理数据后关闭这两个文件。

希望它能帮助

+0

谢谢piotrek。该流确实关闭,它只是不显示在代码片段中。 #1,名称文件不存在,需要在这里创建。 #2,它是一个文件名而不是目录。 #3这就是试图找出原因和解决办法的原因。 – lannyf

0
  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; 
    } 
    

    ,并通知用户如果不。

+0

谢谢格雷戈里!如果newFilePath =(downloadPath +“/”+ fileName);是问题,那么它会有更多的例外。除了这两个版本最终都会调用fixSlashes()。 aga已经提到了外部存储的可用性,不要认为这是设备“下载”文件夹的问题,如果问题是同一个用户/设备会有更多的异常,情况并非如此。 – lannyf

+0

@lannyf MEDIA_MOUNTED问题有点棘手。它只发生在极少数情况下。一种可能的情况是,当用户的设备具有SD卡并且用户通过USB将设备(使用旧的Android)连接到计算机并选择USB连接以传输文件时,可以对其进行测试。 (我的应用程序中有类似的问题,因为我没有SD卡,所以从未发生过这种问题。)“isExternalStorageWritable”由develper.android.com推荐,它很容易实现,所以我会研究它。 – GregoryK

+0

感谢Gregory!它获得了很多报告的实例(对于相同的例外问题)在设备上发生没有SD卡。 – lannyf

0

我希望你的代码在文件中写入数据是完美的我只是集中在你的问题。我认为有两种可能性得到文件没有发现异常。

  1. 当你提供这种性格的当时的文件给出文件名不正确生成,这就是为什么这个错误是发生所以请确保您的文件名是正确的一段时间,文件名是不支持某些特殊字符。
  2. 秒是你的文件扩展名。在这里你没有指定你拥有哪种类型的文件。

这里我有一些代码片段我希望这会帮助你解决问题。

解决方案

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; 
} 

我认为你是聪明的开发者,所以你可以根据你的需求修改这段代码。

最好的运气

+0

谢谢Chirag! '/storage/emulated/0/Download/theFileName.jpg'是报告的异常之一的文件路径。文件名称正确与分机。 – lannyf

+0

@ lannf.Check编辑。 –

0

你没贴全异常堆栈痕迹,但我发现确切的问题这么解决了。

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

使用这个库image-chooser-library. &需要重新因子代码。

这个家伙coomar2841。一定会帮助你。因为他花了数小时解决问题。所以节省你的时间。

接收com.kbeanie.imagechooser的源代码,并将它们放到您的APP中,删除该库的gradle声明并且APP应该可以工作。

请查看​​

我希望它会为你工作。 :)

+0

感谢LukyBoy -KU! FileOutputStream out = new FileOutputStream(newFile);如片段中所指出的那样。 – lannyf

+0

是具体的问题设备?可能是你可以通过GITHUB打开这个问题 –

+0

它不是特定于设备的,它已经在不同的设备上报告过,但显然它也在大多数时间都有效。 – lannyf

相关问题