java 6 IO - 包裹流关闭

时间:2013-05-03 16:32:04

标签: java java-io java-6 try-finally

考虑一下:

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = new FileInputStream(filename); // say no problem
    InputStreamReader reader = new InputStreamReader(file, charsetName);
    BufferedReader buffer = new BufferedReader(reader);
    try {
        buffer.readLine();
    } finally {
        try {
            buffer.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
    }
}

如果new InputStreamReader(file, charsetName)抛出UnsupportedEncodingException,则永远不会调用buffer.close();行。替代方案是额外的冗长:

InputStream file = new FileInputStream(filename);
try {
    InputStreamReader reader = new InputStreamReader(file);
    try {
        BufferedReader buffer = new BufferedReader(buffer);
        try {
            buffer.readLine();
        } finally {
            buffer.close(); // should catch
        }
    } finally {
        reader.close(); // should catch
    }
} finally {
    file.close(); // should catch
}

并且它不必要地关闭所有流(而output.close();应该足够 - 实际上任何一个都应该足够成功 - see comments in the code by Skeet)。

包装构造函数

BufferedReader buffer = new BufferedReader(
              new InputStreamReader(new FileInputStream(filename), charsetName));

基本上只是隐藏了这个问题。

请注意我使用@ TomHawtin-tackline here建议的try-finally惯用语 - 但更常见的方法是:

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = null;
    InputStreamReader reader = null;
    BufferedReader buffer = null;
    try {
        file = new FileInputStream(filename);
        reader = new InputStreamReader(file, charsetName);
        buffer = new BufferedReader(reader);
        buffer.readLine();
    } finally {
        try {
            if(buffer != null) buffer.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
        // Rinse and repeat for the rest
    }
}

很尴尬。

问题:

你如何处理这个案子?
会:

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = new FileInputStream(filename);
    try {
        InputStreamReader reader = new InputStreamReader(file, charsetName);
        BufferedReader buffer = new BufferedReader(reader); // Eclipse warning
        buffer.readLine();
        // notice that if these were out put streams we SHOULD FLUSH HERE
    } finally {
        try {
            file.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
    }
}

吗?换句话说, 关闭最里面的流 (与usually asked相反)将是more than 2时最干净的解决方案包裹的溪流? 是否有finally装饰器也应关闭()的情况?例如,参见点here。请注意Eclipse警告:

  

资源泄漏:“缓冲区”永远不会关闭

Eclipse是对的吗?

这是Java 6 - Android只是Java 6我才提醒你。试图在一些实用程序类中分解IO代码,一劳永逸

2 个答案:

答案 0 :(得分:3)

在上一个方法中,根据关闭流的规则,eclipse显示的Resource leak警告是正确的。关闭最里面的流只关闭该流,而不是关闭该流的其他流。但关闭最外层的流是一次性操作,它将自动关闭所有底层流。 正如文章Always close streams中所述:

  

如果将多个流链接在一起,则关闭其中的一个   是最后一个被建造的,因此处于最高水平   抽象,将自动关闭所有底层流。所以,   一个人只需要在一个流上调用close来关闭(并刷新,   如果适用的话)整个系列的相关流。

所以我认为以下代码是您案例的解决方案:

public static void read(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = null;
    InputStreamReader reader = null;
    BufferedReader buffer = null;
    try 
    {
        file = new FileInputStream(filename);                
        reader = new InputStream(file,charsetName);
        buffer = new BufferedReader(reader);
        buffer.readLine();
    } 
    finally 
    {
         closeQuietly(buffer,reader,file);
    }
}

修改
正如@jtahlborn所建议的,在finally块中编写的代码包含在实用程序方法中,如下所示:

public static void closeQuietly(Closeable... closeables) 
{ 
    if(closeables == null) 
    { 
        return; 
    } 
    for (Closeable c : closeables) 
    { 
        doCloseQuietly(c); 
    } 
} 
public static void doCloseQuietly(Closeable c)
{
    try
    {
        if (c != null)
        {
            c.close();
        }
    }
    catch (IOException ex)
    {
        ex.printStackTrace();
    }
}

答案 1 :(得分:-1)

第二种模式(检查空值1)可以修改为:

public static void readSO2(String filename) throws IOException {
    String charsetName = "UTF-8";
    InputStream file = null;
    InputStreamReader reader = null;
    BufferedReader buffer = null;
    try {
        file = new FileInputStream(filename);
        reader = new InputStreamReader(file, charsetName);
        buffer = new BufferedReader(reader);
        buffer.readLine();
    } finally {
        try {
            if (buffer != null) buffer.close();
            else if (reader != null) reader.close();
            else if (file != null) file.close();
        } catch (IOException e) {
            // report at least
            e.printStackTrace();
        }
    }
}
  • 优点:一次关闭,一次可能异常,无需刷新(输出流)
  • 缺点:仍然不优雅:null舞蹈,必须小心ifs的顺序,没有办法概括

所以问题仍然存在。