[英]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_flush
在fs/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.