【发布时间】:2013-09-13 13:17:27
【问题描述】:
我正在调查 Android 上的一个问题,即由于无法关闭文件而抛出 IOException:
java.io.IOException: close failed: EIO (I/O error)
at libcore.io.IoUtils.close(IoUtils.java:41)
at java.io.FileInputStream.close(FileInputStream.java:121)
at com.adamrosenfield.wordswithcrosses.io.JPZIO.convertJPZPuzzle(JPZIO.java:191)
at com.adamrosenfield.wordswithcrosses.net.AbstractJPZDownloader.download(AbstractJPZDownloader.java:56)
at com.adamrosenfield.wordswithcrosses.net.AbstractJPZDownloader.download(AbstractJPZDownloader.java:41)
at com.adamrosenfield.wordswithcrosses.net.AbstractDownloader.download(AbstractDownloader.java:112)
at com.adamrosenfield.wordswithcrosses.net.AbstractDownloader.download(AbstractDownloader.java:108)
at com.adamrosenfield.wordswithcrosses.net.Downloaders.download(Downloaders.java:257)
at com.adamrosenfield.wordswithcrosses.BrowseActivity.internalDownload(BrowseActivity.java:702)
at com.adamrosenfield.wordswithcrosses.BrowseActivity.access$6(BrowseActivity.java:696)
at com.adamrosenfield.wordswithcrosses.BrowseActivity$7.run(BrowseActivity.java:691)
at java.lang.Thread.run(Thread.java:856)
Caused by: libcore.io.ErrnoException: close failed: EIO (I/O error)
at libcore.io.Posix.close(Native Method)
at libcore.io.BlockGuardOs.close(BlockGuardOs.java:75)
at libcore.io.IoUtils.close(IoUtils.java:38)
... 11 more
相关代码:
public static void convertJPZPuzzle(File jpzFile, File destFile,
PuzzleMetadataSetter metadataSetter) throws IOException {
FileInputStream fis = new FileInputStream(jpzFile);
try {
DataOutputStream dos = new DataOutputStream(new FileOutputStream(destFile));
try {
if (!convertJPZPuzzle(fis, dos, metadataSetter)) {
throw new IOException("Failed to convert JPZ file: " + jpzFile);
}
} finally {
dos.close();
}
} finally {
fis.close();
}
}
完整来源是on GitHub。
从fis.close() 行抛出异常。从阅读 Android 源代码中可以看出,FileInputStream.close() 似乎只是在本机代码的底层文件描述符上调用了close(2)。
手册页似乎没有说明导致EIO 错误的原因,他们只是说“发生了 I/O 错误”之类的内容。或“如果在 close() 期间读取或写入文件系统时发生 I/O 错误”。 Mac OS X 手册页说,当“以前未提交的写入(2)遇到输入/输出错误”时,可能会发生这种情况。在那些系统上。
究竟是什么导致close(2) 因文件描述符错误EIO 而失败,而该文件描述符只为读取而打开,就像在这种情况下一样?显然这不是一个未提交的write(2)。在这个特定文件的情况下,它是使用 Android 的 DownloadManager 服务下载的,这意味着可能存在试图同时访问它的延迟线程和/或进程,但我几乎看不出这会如何影响尝试关闭它。另外,这段代码运行后文件即将被删除(here),但除非 Android 中有一个未记录的时间机器,否则以后的代码应该不会在这里产生影响。
我对 Android 和/或 Linux 上的答案特别感兴趣,但对于其他操作系统的更一般的答案也将不胜感激。
【问题讨论】:
-
在最后一个链接中,您必须在第 429 行找到
close()的实现。 -
@SotiriosDelimanolis:是的,我看到了这个问题——讨论了
EIO错误之后文件描述符的状态;我对EIO的原因 感兴趣,而不是在错误发生后该怎么做。close()的实现是Linux内核内部的系统调用。 -
这似乎与坏 inode 相关,但挖掘内核代码所用的时间比我想象的要长...
-
这里也一样。除了奇异的文件系统之外,我看不到任何
close可以返回EIO的方式。有问题的文件是什么文件系统类型?
标签: java android c linux posix