Java 什么会导致只读文件的EIO关闭(2)失败?
我正在调查Android上的一个问题,其中由于无法关闭文件而引发了Java 什么会导致只读文件的EIO关闭(2)失败?,java,android,c,linux,posix,Java,Android,C,Linux,Posix,我正在调查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.wordswithcrosse
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();
}
}
完整的来源是
正在从行fis.close()
中引发异常。通过阅读Android源代码,我可以看出,FileInputStream.close()
只是调用了本机代码中的底层文件描述符
手册页面似乎没有指定导致EIO
错误的原因,它们只是说“发生了I/O错误”。或者“如果在close()期间读取或写入文件系统时发生了I/O错误”。MacOSX手册页称,在这些系统上,“以前未提交的写入(2)遇到输入/输出错误”时可能会发生这种情况
究竟是什么原因导致仅为读取而打开的文件描述符的close(2)
失败并出现错误EIO
?显然,这不是一个未提交的写入(2)
。在这个特定的文件中,它是使用Android的DownloadManager服务下载的,这意味着可能会有线程和/或进程试图同时访问它,但我几乎看不出这会如何影响关闭它。此外,在代码运行()之后,该文件即将被删除,但除非Android中有一个未记录的时间机器,否则未来的代码不应该在这里产生影响
我对Android和/或Linux上的答案特别感兴趣,但如果能为其他操作系统提供更一般的答案,我将不胜感激。一般来说,在关闭流时,您应该始终预测IOException。代码非常简单,但请参见此处,以获取Java能够提供的最干净的示例: 但是,在您的特定情况下,我认为会引发异常,因为您似乎正在更改unzipOrPassthrough(InputStream)方法中InputStream的值,然后稍后尝试关闭它:
if (entry == null) {
is = new ByteArrayInputStream(baos.toByteArray());
稍后在FileInputStream类上调用close时,它可能会崩溃,因为它现在是ByteArrayInputStream,不再是FileInputStream。我猜
EIO
来自fs/bad\u inode.c
中的bad\u file\u flush
。当内核在访问inode时出现任何故障时,它会将打开的文件描述转换为一个伪打开的文件,并将bad\u inode\u ops
作为其文件ops。我找不到用于基于FAT的文件系统的代码,但可能有一些通用代码
至于原因,可能是连接USB电缆,从连接的计算机上安装文件系统,卸下SD卡等等。我走不了多远,因为我不知道
c
或posix
系统。相关问答。libcore.io
和close
的native
实现(用于fd)的源代码。在最后一个链接中,您必须在第429行找到close()
的实现。@SotiriosDelimanolis:是的,我看到了在EIO
错误后讨论文件描述符状态的问题;我感兴趣的是什么导致了EIO
,而不是错误发生后该怎么办。close()
的实现是Linux内核内部的一个系统调用。它似乎与一个坏的inode有关,但是挖掘内核代码所花费的时间比我想象的要长一点……这里也一样。我不认为close
可以通过EIO
返回任何方法,除了外来的文件系统。有问题的文件是什么文件系统类型的?它甚至没有意义。如果它现在是一个ByteArrayInputStream
对象,他就不能“以后调用FileInputStream
类上的close”。他正在通过tearrayinputstream关闭。时期关于“现在是一个ByteArrayInputStream
而不再是一个FileInputStream
的部分是毫无意义的。引用的类型为InputStream。
对对象的引用无法记住它们指向的对象的类型。unzipOrPassthrough()
读取传入的输入流,但不会关闭它。它确实重新分配了本地参数is
,但这对传入的原始流没有影响。不幸的是,我无法访问用户的设备,因此我无法确定到底发生了什么,但在此之前,这似乎是最有可能的解释。在浏览内核源代码一段时间后,似乎sys\u close()
只能返回0、-EINTR
、-EBADF
,或者文件系统flush()
实现的返回值,vfat
没有实现flush()
。