简体   繁体   English

close是否会抛出IOException?

[英]Does close ever throw an IOException?

After providing some answers here, and reading some comments, it would seem that, in practice IOException is never thrown on close for file I/O. 在这里提供了一些答案并阅读了一些注释后,似乎实际上IOException永远不会在文件I / O上关闭。

Are there any cases in which calling close on a Stream/Reader/Writer actually throws an IOException? 是否有任何情况下,在Stream / Reader / Writer上调用close实际上会抛出IOException?

If an exception is actually thrown, how should it be dealt with? 如果实际抛出异常,应如何处理?

I have found two cases: 我发现了两个案例:

  • Losing the network connection when there is still data in the buffer to be flushed. 当要刷新的缓冲区中仍有数据时丢失网络连接。
  • Having the file system fill up (or reaching your user limit for file size) when there is still data in the buffer to be flushed. 当缓冲区中仍有数据要刷新时,让文件系统填满(或达到文件大小的用户限制)。

Both of those examples depend on something happening while there is still data in the buffer. 这两个示例都依赖于缓冲区中仍有数据时发生的事情。 Close flushes the buffer before the file is closes, so if there is an error writing the data to the file it throws an IOException. 在文件关闭之前关闭刷新缓冲区,因此如果将数据写入文件时出错,则会抛出IOException。

If you execute the following code passing it the name of a file to create on a network drive, and then before you press the enter key unplug your network cable, it will cause the program to throw an IOException in close. 如果执行以下代码,将其传递给要在网络驱动器上创建的文件的名称,然后在按Enter键之前拔下网络电缆,则会导致程序在关闭时抛出IOException。

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Test
{
    public static void main(final String[] argv)
    {
        final File file;

        file = new File(argv[0]);
        process(file);
    }

    private static void process(final File file)
    {
        Writer writer;

        writer = null;

        try
        {
            writer = new FileWriter(file);
            writer.write('a');
        }
        catch(final IOException ex)
        {
            System.err.println("error opening file: " + file.getAbsolutePath());
        }
        finally
        {
            if(writer != null)
            {
                try
                {
                    try
                    {
                        System.out.println("Please press enter");
                        System.in.read();
                    }
                    catch(IOException ex)
                    {
                        System.err.println("error reading from the keyboard");
                    }

                    writer.close();
                }
                catch(final IOException ex)
                {
                    System.err.println("See it can be thrown!");
                }
            }
        }
    }
}

Since Java 7 you can use try-with-resources to get out of this mess (removed explicit exception generation code for the close() operation): 从Java 7开始,您可以使用try-with-resources来摆脱这种混乱(删除了close()操作的显式异常生成代码):

private static void process(final File file) {
    try (final Writer writer = new FileWriter(file)) {
        writer.write('a');
    } catch (final IOException e) {
        // handle exception
    }
}

this will auto-magically handle the exceptions in close() and it performs an explicit null check internally. 这将自动神奇地处理close()的异常,并在内部执行显式null检查。

When it does happen, it should be handled like any other IOException , not silently ignored like you see recommended so often. 当它确实发生时,它应该像任何其他IOException一样处理,而不是像你经常看到推荐那样默默地被忽略。 The assumption is, I guess, that since you're done using the stream, it doesn't matter if it was cleaned up properly. 我猜这个假设是,既然你已经完成了使用流,那么它是否被正确清理并不重要。

However, cleaning up properly is important. 但是,正确清理很重要。 If a close() operation does raise an exception, its likely that it involved flushing some output, committing some transaction (in the case of a database connection you thought was read-only), etc.—definitely not something that should be ignored. 如果close()操作确实引发异常,则可能是它涉及刷新某些输出,提交某些事务(在数据库连接的情况下,您认为是只读的)等等 - 绝对不应该忽略。 And, since it is rare, you're not compromising the reliability of your application significantly by aborting the operation. 而且,由于这种情况很少见,因此您不会通过中止操作来显着降低应用程序的可靠性。

For files, you may not see IOException thrown often on close(), but you'll definitely see it for non-File I/O like closing sockets to the network. 对于文件,您可能看不到在close()上经常抛出的IOException,但您肯定会看到非文件I / O,如关闭网络套接字。

Here's an example of a Java bug where closing a UDP socket eventually caused an IOException to be thrown. 下面是一个Java错误示例 ,其中关闭UDP套接字最终导致抛出IOException。

It's specifically FileInputStream.close which does not throw, even if your hard drive is on fire. 它特别是FileInputStream.close ,它不会抛出,即使你的硬盘驱动器着火了。 Presumably it is the same for socket input. 据推测,套接字输入是一样的。 For output streams you may also be flushing. 对于输出流,您也可能正在刷新。 Until relatively recently [see timestamps] BufferedOutputStream used to fail to close the underlying stream if flush threw. 直到最近[查看时间戳] BufferedOutputStream用于在flush抛出时无法关闭底层流。

(@MaartenBodewes would like me to point out that FileInputStream.close not throwing is not specified by the API docs. At the time of the post it was customary to elide the clause mentioning that this related to the Sun JDK (now known as Oracle JDK and OpenJDK). It appears that an obscure former reimplementation called Apache Harmony which Android used to use may have had different behaviour. Potentially other implementations, or versions of OpenJDK, may also throw.) (@MaartenBodewes希望我指出API文档没有指定不抛出的FileInputStream.close 。在帖子发布时,通常会忽略提及这与Sun JDK(现在称为Oracle JDK)相关的条款看起来,Android曾经使用的一个名为Apache Harmony的模糊的前重新实现可能有不同的行为。可能还有其他实现,或OpenJDK的版本,也可能抛出。)

检查调用close时会发生什么,异常隐藏如何影响你以及你可以做些什么: 博客文章

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

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