什么会导致 close(2) 对于只读文件使用 EIO 失败?

2023-12-28

我正在调查 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();
    }
}

完整来源是在 GitHub 上 https://github.com/adamantoise/wordswithcrosses/blob/master/wordswithcrosses/src/com/adamrosenfield/wordswithcrosses/io/JPZIO.java.

异常正在从线路中抛出fis.close()。从我阅读 Android 源代码可以看出,它看起来像FileInputStream.close()只是向下调用close(2) http://linux.die.net/man/2/close在本机代码中的底层文件描述符上。

手册页似乎没有指定什么会导致EIO错误,他们只是说“发生 I/O 错误”之类的内容。或“如果在 close() 期间读取或写入文件系统时发生 I/O 错误”。 Mac OS X 手册页称,当“先前未提交的写入(2)遇到输入/输出错误”时,可能会发生这种情况。在这些系统上。

到底是什么原因造成的close(2)因错误而失败EIO对于仅打开用于读取的文件描述符,如本例所示?显然这不是一个不承诺的write(2)。就这个特定文件而言,它是使用 Android 的 DownloadManager 服务下载的,这意味着可能存在延迟线程和/或进程试图同时访问它,但我几乎看不出这会如何影响尝试关闭它。另外,此代码运行后该文件即将被删除(here https://github.com/adamantoise/wordswithcrosses/blob/master/wordswithcrosses/src/com/adamrosenfield/wordswithcrosses/net/AbstractJPZDownloader.java#L58),但除非 Android 中有一个未记录的时间机器,否则未来的代码不应该对这里产生影响。

我对 Android 和/或 Linux 上的答案特别感兴趣,但对于其他操作系统的更一般的答案也将受到赞赏。


我猜EIO来自bad_file_flush in fs/bad_inode.c。似乎当内核访问索引节点失败时,它会将打开的文件描述转换为带有以下内容的伪打开文件bad_inode_ops作为其文件操作。我找不到为基于 FAT 的文件系统执行此操作的代码,但也许有一些通用代码。

至于原因,可能是连接 USB 电缆并从连接的计算机安装文件系统、移除 SD 卡等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么会导致 close(2) 对于只读文件使用 EIO 失败? 的相关文章

随机推荐