簡體   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