为啥有时会抛出 FileNotFoundException
Posted
技术标签:
【中文标题】为啥有时会抛出 FileNotFoundException【英文标题】:why sometime it throws FileNotFoundException为什么有时会抛出 FileNotFoundException 【发布时间】:2016-03-04 05:19:54 【问题描述】:代码大部分时间都能正常工作,但有时会抛出异常。不知道是什么原因造成的。
要做的是在
处创建一个文件/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)
【问题讨论】:
可能没有完成它的创建,您尝试访问它。每次应用打开时,它都会尝试创建一个文件并从中读取? 尝试替换:File newFile = new File(downlaodDirectory, fileName); Lispas,应用程序一直在运行。 mdtuyen, File newFile = new File(downlaodDirectory, fileName);没有帮助,如果同时具有 downlaodDirectory 和 fileName,则它与 new File(downlaodDirectory.getPath()+"/"+ fileName); 相同 FileInputStream 不创建文件。那么为什么会有这样的声明呢?你在做什么?从您的帖子中不清楚该异常是来自输入流还是输出流。 此错误是否出现在同一设备上?还是有些设备出错,有些设备没有? 【参考方案1】:我可以想到这种行为的以下可能原因:
-
无法创建新文件,因为 SD 卡上没有可用空间。下次遇到此问题时,请尝试通过文件管理器或“设置”->“存储”查看是否至少有一些可用空间。如果这是在您的用户设备上发生的情况,我怀疑您可以做些什么。
SD 卡由于某些操作系统故障或物理上未连接而无法使用,因此无法创建文件。再说一次 - 除了显示一些带有错误消息的
Toast
之外,您无能为力。
如何生成文件路径的fileName
部分? Sometimes 无法创建文件,因为文件名包含(此特定设备)不支持的字符。例如。我有 Android 4.1.2 的 HTC Desire X,如果文件名包含冒号,则无法使用与您的代码相似的代码创建文件。尝试另一种方法来生成文件名,看看是否有区别。
在创建文件之前,您确定Downloads
目录存在吗?写如下内容:
if (!downloadDirectory.exists())
downloadDirectory.mkdirs();
WRITE_EXTERNAL_STORAGE
权限在 Android 6 上被视为dangerous,因此用户可以随时撤销它。 Make sure 用户在写入文件之前没有撤销此权限。
Always close the I/O stream 当你完成它的工作时。将 finally
子句添加到您的 try-catch 块并关闭其中的 in
和 out
流:
finally
if (in != null)
try
in.close();
catch (Exception e)
if (out != null)
try
out.close();
catch (Exception e)
最后一个 - 最后我别无选择。 :) 我想如果您从多个线程写入同一个文件,也可能会出现此问题。如果是这种情况,请尝试同步对您的文件编写代码的访问。
【讨论】:
再次感谢!崩溃是从 crashlytics 报告的,并且实例显示设备似乎没有内存不足。这可能是一个小故障,但有数百个报告。文件名就一个字就可以了。它不喜欢系统下载目录不存在,如果存在,那么同一个用户将报告多个实例,但事实并非如此。用户可以撤销 write_external_storage,但实例分布来自所有不同的设备。再次感谢您列出可能性。 @lannyf 我又忘记了一个机会:当您完成与in
和out
流的合作时,您并没有关闭它们。也试试这个。
再次感谢您。它确实关闭了流,但没有显示在代码 sn-p 中。
@lannyf 检查您是否不会同时从不同线程写入同一个文件。这是我能想到的最后一个选择。 :)
想不出是否有多个线程试图在这里写入同一个文件。当它到达这里时,生成的输出文件名是唯一的,并检查可能正在进行的文件以获得这里唯一的新名称。感谢您指出这一点!【参考方案2】:
根据 Java 文档 - Class FileNotFoundException:
public class FileNotFoundException extends IOException
表示尝试打开由指定路径名表示的文件失败的信号。
这个异常会被
FileInputStream
抛出,FileOutputStream
和RandomAccessFile
构造函数,当文件包含 指定的pathname
不存在。也会被这些抛出 构造函数,如果文件确实存在但由于某种原因是 不可访问,例如当试图打开一个只读的 写文件。
要恢复,在三种情况下可能会抛出 FileNotFoundException
。
-
指定的文件不存在。
命名文件实际上是一个目录。
由于某种原因,无法打开指定文件进行读取。
新创建的文件出现“文件不存在”异常。
在你的代码中我没有看到两件事
-
成功写入后删除文件。我一点也不在开玩笑。如果我有这样和那样的错误,我会做一个测试,在从源文件复制内容后删除
downlaodDirectory
。在这种情况下,它会通过该方法,或者您会得到另一个但更具体的错误 - 就像我的话:无法删除文件。正在使用中
写入数据后关闭文件。我也没有看到关闭文件的方法。在您的代码中,您的文件似乎仍处于打开状态,因此您再次运行一个应用程序,您会因为错误而无法预料。
要解决此问题,只需在使用 file.close()
方法处理数据后关闭这两个文件即可。
希望对你有帮助
【讨论】:
感谢 piotrek。流确实关闭了,只是没有显示在代码 sn-p 中。 #1,name文件不存在,需要在这里创建。 #2,它是文件名而不是目录。 #3 这就是试图找出原因并解决它的方法。【参考方案3】:由于您创建文件的方式可能会发生此问题:
String downloadPath = downloadDirectory.getPath();
String newFilePath = (downloadPath + "/" + fileName);
File newFile = new File(newFilePath);
危险代码在这里:
String newFilePath = (downloadPath + "/" + fileName);
请尝试使用以下方法:
File newFile = new File(downloadDirectory, fileName);
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;
如果没有则通知用户。
【讨论】:
感谢格雷戈里! if newFilePath = (downloadPath + "/" + fileName);是问题,那么它会有更多的例外。除了这两个版本最终都调用了 fixSlashes()。 aga 已经提到了外部存储的可用性,不要认为这是设备的“下载”文件夹的问题,如果问题是相同的用户/设备会有更多的例外,事实并非如此。 @lannyf MEDIA_MOUNTED 问题有点棘手。它仅在极少数情况下发生。一种可能的情况,因此您可以测试它,当用户的设备有 SD 卡并且用户通过 USB 将设备(使用旧 Android)连接到计算机并选择 USB 连接以传输文件时。 (我的应用程序中遇到过类似的问题,因为我没有 SD 卡,所以从未发生过。) develper.android.com 推荐“isExternalStorageWritable”,它非常容易实现,所以我会研究一下。跨度> 谢谢格雷戈里!它在没有 SD 卡的设备上发生了很多报告的实例(对于相同的异常问题)。【参考方案4】:您没有发布完整的异常堆栈跟踪,但我发现 SO 解决了确切的问题。
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 应该可以工作。
请查看GitHub Issue
我希望它对你有用。 :)
【讨论】:
感谢 LukyBoy -KU!例外是 FileOutputStream out = new FileOutputStream(newFile);正如 sn-p 中所指出的那样。 问题设备是否特定?也许你可以通过 GITHUB 打开这个问题 它不是特定于设备的,它已在不同的设备上报告过,但显然它在大多数情况下也有效。 只有你能解决,只需深入挖掘,投我一票:)【参考方案5】:我希望你在文件中写入数据的代码是完美的,我只是专注于你的问题。我认为有两种可能性得到 File not found Exception。
-
有时文件名不支持某些特殊字符当您提供这种字符以提供文件名时,文件未正确生成,这就是发生此错误的原因所以请确保您的文件名正确。李>
第二个是你的文件扩展名。这里你没有指定你有哪种文件。
这里有一些代码片段,希望能帮助您解决问题。
解决方案
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 我不知道您的代码到底发生了什么,但我有一个代码 sn-p,它只是从 soundcloude 下载 mp3 文件并存储在我的本地存储中。我认为它与您的要求完全相同。所以我在下面发布了我的代码。
@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;
我认为您是聪明的开发人员,因此您可以根据需要修改此代码。
祝你好运
【讨论】:
感谢奇拉格! '/storage/emulated/0/Download/theFileName.jpg' 是报告的异常之一的文件路径。文件名很好,有适当的分机。【参考方案6】:还有一种可能:
如果您的代码的一部分正在写入文件而另一部分正在读取,那么最好在写入者完成文件写入之前考虑读取器正在读取。
您可以通过将代码置于调试模式来交叉检查这种情况。如果它在那里工作正常并给你 FileNotFoundException,那么这肯定是这个异常的潜在原因。
现在,如何解决:
您可以使用类似于以下代码块的重试机制
if(!file..exists())
Thread.sleep(200);
在您的代码中并根据您的需要更改睡眠值。
希望对您有所帮助。!!
【讨论】:
以上是关于为啥有时会抛出 FileNotFoundException的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的比较方法有时会抛出 IllegalArgumentException?
为啥我的线程池有时会抛出 `std::bad_function_call` 或 `double free or corruption (!prev)`
为啥 FileOutputStream 会抛出 FileNotFoundException?
为啥“prepareCall”会抛出 NumberFormatException?