【问题标题】:What is the proper way to open a stream in Java在Java中打开流的正确方法是什么
【发布时间】:2012-04-15 02:29:30
【问题描述】:

我将为物理专业的学生进行 Java 讲座,我想知道如何正确打开文件。

在我的许多专业应用程序中,我都做过类似的事情:

  BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file")));
  try{
    ....
  }finally {
     bufferedWriter.close();
  }

恕我直言,好的,即阅读器将始终关闭。

当我为我的学生举这个例子时,我想知道如果 InputStreamReader 的构造函数会抛出异常会发生什么 --- FileInputStream 将打开,但我的代码不会关闭它(因为这些对象在 try-finally 块之外创建。

这是正确的成语,如果是,为什么?如果打开流不是正确的习惯用法,请指出正确的习惯!

编辑:我正在寻找既正确又易于编写和理解的成语,物理专业的学生是编程的初学者。

编辑:愚蠢的我,我复制了错误的示例 --- 如果我使用 Writers 而不是 Readers,它会变得更加复杂。

【问题讨论】:

    标签: java java-io


    【解决方案1】:

    使用输入流读取

    在 Java 7 之前你会这样做

    InputStream in = null;
    try {
         in = new FileInputStream("simple.csv");
         BufferedReader buf = new BufferedReader(new InputStreamReader(in));
    } finally {
      if (in != null) {
         try {
             in.close();
         } catch (IOException e) {}
      }
    }
    

    对于 Java 7,您可以使用 Closeable,类似

    try (BufferedReader buf = new BufferedReader(...)) {}
    

    编辑:为什么我没有关闭上面的buf?看看BufferedReader.close()的源代码

    public void close() throws IOException {
        synchronized (lock) {
            if (in == null)
                return;
            in.close();
            in = null;
            cb = null;
        }
    }
    

    使用输出流编写

    编辑 2:同样的原则适用于作家。但是,如果您真的有兴趣在出现IOException 时刷新流,那么您必须同时检查writer 和stream 中的null 并尝试分别关闭它们。但是,这提供了很多额外的代码。它可能看起来像这样:

    BufferedWriter buf = null;
    OutputStream out = null;
    try {
        out = new FileOutputStream("file");
        buf = new BufferedWriter(new OutputStreamWriter(out));
    } finally {
      if (buf != null) {
         try { buf.close(); } catch (IOException ex){}
      }
      if (out != null) {
         try { out.close(); } catch (IOException ex){}
      }
    }
    

    这不是很漂亮。您可以引入一个辅助例程来关闭您的流或查看 Java 7 或 Apache IOUtils

    【讨论】:

    • 不完全......(编辑:没关系,你已经解决了我的两个反对意见。我会使用BufferedReader buf = null 只是为了明确)
    • 如果InputStreamReader 会抛出异常,这不会关闭流。你最终也会导致另一个NullPointerException,因为buf在这里可能是null。
    • @RenéJeschke,感谢您的关注,我的定位不够详细,我会修复它。
    • @jb。正确的。除非您想重用缓冲的阅读器,否则我认为这样做没有意义。你当然可以,就像 in 正在测试和关闭一样。
    • AFAIK 有 --- 因为在关闭缓冲区被刷新之前。
    【解决方案2】:

    在这种特殊情况下(嵌套构造函数),FileInputStream 将保持打开状态。你必须这样做(如果你真的需要确保流被关闭):

    final FileInputStream fis = new FileInputStream("");
    try
    {
        final BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        // ...
    }
    finally
    {
        fis.close();
    }
    

    关闭FileInputStream 就足够了。

    编辑:同样的逻辑可以应用于作家。如果打开 FileOutputStream 失败,它会抛出一个异常,阻止 try/finally 块的执行。如果任何其他写入器构造函数失败,输出流仍然会通过final 子句关闭。

    【讨论】:

    • 真的,我只需要找到正确的代码示例,我不确定在 FileInputStream 构造函数中检查错误的额外代码行是否值得。
    • 另一方面,我们预计会出现异常的唯一地方是 FileInputStream 的构造函数,因为它要打开的文件可能不存在。
    猜你喜欢
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 2015-05-06
    • 2017-01-11
    相关资源
    最近更新 更多