Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中关闭嵌套流和写入程序的正确方法_Java_Java Io - Fatal编程技术网

在Java中关闭嵌套流和写入程序的正确方法

在Java中关闭嵌套流和写入程序的正确方法,java,java-io,Java,Java Io,注意:这个问题及其大部分答案都可以追溯到Java 7发布之前。Java7提供了易于实现的功能。如果您使用的是Java 7或更高版本,则应升级到 在Java中,关闭嵌套流的最佳、最全面的方法是什么?例如,考虑设置: FileOutputStream fos = new FileOutputStream(...) BufferedOS bos = new BufferedOS(fos); ObjectOutputStream oos = new ObjectOutputStream(bos);

注意:这个问题及其大部分答案都可以追溯到Java 7发布之前。Java7提供了易于实现的功能。如果您使用的是Java 7或更高版本,则应升级到


在Java中,关闭嵌套流的最佳、最全面的方法是什么?例如,考虑设置:

FileOutputStream fos = new FileOutputStream(...)
BufferedOS bos = new BufferedOS(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
我理解封闭式操作需要投保(可能使用最终条款)。我想知道的是,是否有必要明确地确保嵌套流是关闭的,或者只确保关闭外部流(oos)就足够了

我注意到的一件事,至少在处理这个特定的示例时,是内部流似乎只抛出FileNotFoundException。这似乎意味着,从技术上讲,如果它们失败了,就没有必要担心关闭它们

一位同事写道:


从技术上讲,如果实施得当,关闭最外层 流(oos)应该足够了。但实施似乎有缺陷

例如: BufferedOutputStream从FilterOutputStream继承close(),后者将其定义为:

 155       public void close() throws IOException {
 156           try {
 157             flush();
 158           } catch (IOException ignored) {
 159           }
 160           out.close();
 161       }
但是,如果flush()出于某种原因引发运行时异常,则 永远不会调用out.close()。因此,这似乎是最“安全”(但丑陋)的 主要是担心关闭FOS,这会使文件保持打开状态


当您绝对需要确定关闭嵌套流的方法时,什么方法被认为是最好的


有没有正式的Java/Sun文档可以详细处理这个问题?

关闭链接流时,只需关闭最外层的流。任何错误都将向上传播并被捕获

有关详细信息,请参阅

解决这个问题

但是,如果flush()出于某种原因引发运行时异常,则永远不会调用out.close()

这是不对的。捕获并忽略该异常后,执行将在catch块之后重新开始,并将执行
out.close()
语句


您的同事对运行时异常提出了一个很好的观点。如果您确实需要关闭流,您可以尝试从外向内逐个关闭每个流,在出现第一个异常时停止。

该同事提出了一个有趣的观点,并且有理由进行争论


就我个人而言,我会忽略
运行时异常
,因为未检查的异常表示程序中存在错误。如果程序不正确,请修复它。你不能在运行时“处理”一个坏程序。

我通常做以下事情。首先,定义一个基于模板方法的类来处理try/catch混乱

import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public abstract class AutoFileCloser {
    // the core action code that the implementer wants to run
    protected abstract void doWork() throws Throwable;

    // track a list of closeable thingies to close when finished
    private List<Closeable> closeables_ = new LinkedList<Closeable>();

    // give the implementer a way to track things to close
    // assumes this is called in order for nested closeables,
    // inner-most to outer-most
    protected final <T extends Closeable> T autoClose(T closeable) {
            closeables_.add(0, closeable);
            return closeable;
    }

    public AutoFileCloser() {
        // a variable to track a "meaningful" exception, in case
        // a close() throws an exception
        Throwable pending = null;

        try {
            doWork(); // do the real work

        } catch (Throwable throwable) {
            pending = throwable;

        } finally {
            // close the watched streams
            for (Closeable closeable : closeables_) {
                if (closeable != null) {
                    try {
                        closeable.close();
                    } catch (Throwable throwable) {
                        if (pending == null) {
                            pending = throwable;
                        }
                    }
                }
            }

            // if we had a pending exception, rethrow it
            // this is necessary b/c the close can throw an
            // exception, which would remove the pending
            // status of any exception thrown in the try block
            if (pending != null) {
                if (pending instanceof RuntimeException) {
                    throw (RuntimeException) pending;
                } else {
                    throw new RuntimeException(pending);
                }
            }
        }
    }
}
使用这种方法,您不必担心try/catch/finally会再次关闭文件


如果这对于您的使用来说太重,至少考虑一下try/catch和它使用的“挂起”变量方法。

这是一个令人惊讶的尴尬问题。(即使假定
acquire;try{use;}最终{release;}
代码是正确的。)

如果decorator的构造失败,那么就不会关闭底层流。因此,您确实需要显式地关闭底层流,无论是在finally-after-use中,还是在将资源成功地移交给decorator后的更多diifult中)

如果异常导致执行失败,是否确实要刷新

有些装饰师实际上自己也有资源。例如,
ZipInputStream
的当前Sun实现分配了非Java堆内存

有人声称(IIRC)Java库中三分之二的资源使用的实现方式明显不正确

BufferedOutputStream
即使在
flush
IOException
上也会关闭时,
BufferedWriter
会正确关闭

我的建议是:尽可能直接关闭资源,不要让它们污染其他代码。OTOH,您可能会在这个问题上花费太多的时间-如果抛出
OutOfMemoryError
,表现良好是很好的,但是您程序的其他方面可能具有更高的优先级,并且在这种情况下库代码可能会被破坏。但我总是写:

final FileOutputStream rawOut = new FileOutputStream(file);
try {
    OutputStream out = new BufferedOutputStream(rawOut);
    ... write stuff out ...
    out.flush();
} finally {
    rawOut.close();
}
(看:没有接球!)


也许可以使用executearound习惯用法。

Sun的JavaDocs在文档中包括
RuntimeException
s,如InputStream的方法所示;记录为引发NullPointerException和IndexOutOfBoundsException

FilterOutputStream只记录为引发IOException,因此它实际上不会引发任何
RuntimeException
s。任何可能被抛出的东西都很可能被包裹在一个盒子里


它仍然可以抛出一个错误,但你对此无能为力;Sun建议您不要试图捕捉它们。

此外,您不必关闭所有嵌套流

检查这个

使用Apache Commons处理IO相关对象是一种很好的做法

finally
子句中,使用
IOUtils

IOUtils.closequity(bWriter); 安静地关上(Owriter)

下面是代码片段

BufferedWriter bWriter = null;
OutputStreamWriter oWritter = null;

try {
  oWritter  = new OutputStreamWriter( httpConnection.getOutputStream(), "utf-8" );
  bWriter = new BufferedWriter( oWritter );
  bWriter.write( xml );
}
finally {
  IOUtils.closeQuietly(bWriter);
  IOUtils.closeQuietly(oWritter);
}
JavaSE7似乎没有被提及。这样就不需要显式地完全关闭,我非常喜欢这个想法

不幸的是,对于Android开发来说,只有使用Android Studio(我认为)才能获得这种甜蜜的体验。

在Java 7时代,这无疑是一条路要走。正如前面几个答案中提到的,关闭请求从最外层的流传播到最内层的流。所以只需要一次收盘

try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
  // do something with ois
}
然而,这种模式存在一个问题。try-with-resources不知道内部FileInputStream,因此如果ObjectInputStream构造函数引发异常,FileInputStream将永远不会关闭(直到垃圾回收器启动)
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
  // do something with ois
}
try (FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis)) {
  // do something with ois
}
public class StreamTest {

public static void main(String[] args) {

    FileOutputStream fos = null;
    BufferedOutputStream bos = null;
    ObjectOutputStream oos = null;

    try {
        fos = new FileOutputStream(new File("..."));
        bos = new BufferedOutputStream(fos);
        oos = new ObjectOutputStream(bos);
    }
    catch (Exception e) {
    }
    finally {
        Stream.close(oos,bos,fos);
    }
  }   
}

class Stream {

public static void close(AutoCloseable... array) {
    for (AutoCloseable c : array) {
        try {c.close();}
        catch (IOException e) {}
        catch (Exception e) {}
    }
  } 
}