繁体   English   中英

对于只读文件,什么可能导致close(2)失败EIO?

[英]What can cause close(2) to fail with EIO for a read-only file?

我正在调查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上

fis.close()行抛出异常。 从我从阅读Android源代码可以看出,看起来像FileInputStream.close()只是在本机代码中的底层文件描述符上调用close(2)

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

究竟是什么导致close(2)失败并且错误EIO对于只打开读取的文件描述符,就像在这种情况下一样? 显然,这不是一个未提交的write(2) 在这个特定文件的情况下,它是使用Android的DownloadManager服务下载的,这意味着可能存在挥之不去的线程和/或进程试图同时访问它,但我几乎看不出这将如何影响尝试关闭它。 此外,该代码运行( 此处 )后即将删除该文件,但除非Android中有未记录的时间机器,否则将来的代码不应该有影响。

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

我猜EIO来自bad_file_flushfs/bad_inode.c 当内核访问inode时出现任何故障时,它会将打开的文件描述转换为带有bad_inode_ops的伪打开文件作为其文件操作。 我找不到为基于FAT的文件系统执行此操作的代码,但也许有一些通用代码。

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

通常,在关闭流时应始终预期IOExceptions。 代码非常简单,但请看这里Java可以提供的最干净的示例:

https://stackoverflow.com/a/156520/1489860

但是,在您的特定情况下,我想会抛出一个异常,因为它似乎是在unzipOrPassthrough(InputStream)方法中更改InputStream的值,然后尝试关闭它:

        if (entry == null) {
        is = new ByteArrayInputStream(baos.toByteArray());

当你稍后在FileInputStream类上调用close时,它可能会吓坏,因为它现在是ByteArrayInputStream而不再是FileInputStream。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM