【问题标题】:Close In/OutputStream in Java在 Java 中关闭输入/输出流
【发布时间】:2021-03-09 10:12:02
【问题描述】:

如你所见,我确实关闭了 fooo,所以在那之后我需要关闭 OutputStream 吗? :

public void writedata(List<sinhvien> svlist) {
    FileOutputStream fo = null;
    ObjectOutputStream oo = null;
    try {
        fo = new FileOutputStream(datasv);
        oo = new ObjectOutputStream (fo);
        oo.writeObject(svlist);
    }
    catch (IOException e) {}
    
    finally {
            try {
                fo.close();
                oo.close();
            }
            catch (IOException e ) {}
    }
}

类似的东西:... OutputStream os if (os != null ) try { os.close() } ... 有必要吗?

【问题讨论】:

  • 1,你应该使用try-with-resources 2,在ObjectOutputStream上调用close也会关闭底层OutputStream
  • 如果类实现了AutoCloseableCloseable 并且它已被初始化,那么它可以并且应该被关闭(除非使用带有AutoCloseable 接口的try-with-resources)。这可以通过搜索每个类并检查文档来简单地找到。因此,否决了这个问题。
  • 但是,在您的情况下,您将一个流嵌入到另一个流中,因此当您关闭一个流时,您将关闭底层流。
  • 谢谢你们,伙计们!我明白了!

标签: java inputstream outputstream


【解决方案1】:

你做错了顺序。

流被允许缓冲。通过首先关闭底层流 (fo),如果 oo 缓冲,您的代码将失败。你还在吃任何异常,这显然是一个非常糟糕的主意:如果你的代码失败(例如,oo close 抛出一个异常,报告它未能写出最后几个字节,因为 fo 已经关闭,你'我永远不知道,现在您有一个损坏的文件,但不知道它已损坏。

您可以关闭oo 并完成它,但问题是,如果oo = new ObjectOutputStream(fo) 失败怎么办?你仍然需要关闭fo

课程:

  1. 您必须按堆栈顺序关闭您打开的每个资源(您所做的最后一件事需要先关闭)。
  2. 永远不要写一个空的 catch 块,除非你真的,真的,真的知道你在做什么。

应用这些课程的最佳方式:

  1. 使用 try-with-resources
  2. 在您的签名上随意乱扔throws IOException 等。您的main 应声明为throws Exception。在不可行或不可能的情况下,正确的“我不知道发生了什么”catch 块是:`catch (Thingie e) { throw new RuntimeException("uncaught", e);

因此:

public void writedata(List<sinhvien> svlist) throws IOException {
    try (var fo = new FileOutputStream(datasv);
         var oo = new ObjectOutputStream(fo)) {

        oo.writeObject(svlist);
    }
}

要好几个数量级:

  1. 它没有缓存问题
  2. 阅读和遵循要容易得多
  3. 一个名为“writeData”的方法显然可以以另一种方式退出:嗯,哎呀,我保存它的 I/O 系统出现问题。方法应该抛出看起来很明显的东西,IOException 在这里很明显。
  4. 保存数据失败时不会静默不做任何事情。

【讨论】:

    【解决方案2】:

    您可以对资源使用 try 并取消显式关闭调用 类似的东西

    public void writeData(final List<Sinhvein> svList){
        try(final FileOutputStream fo = new FileOutputStream(datasv); final ObjectOutputStream oo = new ObjectOutputStream(fo);){
        // do something with fo and oo
        }
    }
    

    尝试资源的全部意义在于避免显式 finally 块负责清理。

    【讨论】:

    • 所以你的意思是:只需简单地添加 final 而不需要 close 任何东西?
    • 不,final 只是一个限定符,以确保变量没有绑定到另一个对象。将初始化包含在 try 本身中将负责关闭打开的资源
    • 好的,我知道了。我刚刚在 docs.oracle 中阅读了“尝试使用资源”..
    • 无论如何,如果我继续使用我的旧方式,你认为我需要 close OutputStream 吗?还是只关闭 fooo 就足够了?
    猜你喜欢
    • 2015-06-18
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-26
    • 1970-01-01
    相关资源
    最近更新 更多