java 6 IO - wrapped streams closing [closed]

不羁岁月 提交于 2019-12-20 07:48:40

问题


Consider :

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();
        }
    }
}

If new InputStreamReader(file, charsetName) throws UnsupportedEncodingException, the buffer.close(); line will never be called. The alternative is extra verbose :

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
}

and it needlessly closes all streams (while output.close(); should suffice - actually any of them should suffice if successful - see comments in the code by Skeet).

Wrapping the constructors

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

is essentially just hiding the problem.

Notice I use the try-finally idiom suggested by @TomHawtin-tackline here for instance - but the more common approach :

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
    }
}

is as awkward.

Question :

How would you handle this case ?
Would :

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();
        }
    }
}

do ? In other words closing the innermost stream (contrary to what is usually asked) would be the cleanest solution when there are more than 2 wrapped streams ? Are there cases when finally the decorator should be also closed() ? See for instance points here. Notice that Eclipse warns :

Resource leak: 'buffer' is never closed

Is Eclipse right ?

This is Java 6 - Android is Java 6 only I remind you. Trying to factor out IO code in some utility classes, once and for all


回答1:


In your last approach , Resource leak warning as shown by eclipse is correct according to the rules of closing streams. closing the innermost stream is only closing that stream but not the other streams that has wrapped up that stream. But closing the outermost stream is one time operation that will automatically close all the underlying streams. As specified in the article Always close streams :

If multiple streams are chained together, then closing the one which was the last to be constructed, and is thus at the highest level of abstraction, will automatically close all the underlying streams. So, one only has to call close on one stream in order to close (and flush, if applicable) an entire series of related streams.

So In my opinion following code is solution for your case:

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);
    }
}

EDIT
As suggested by @jtahlborn the code written within finally block is wrapped within a utility method as follows:

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();
    }
}



回答2:


The second pattern (the check for null one) could be amended as :

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();
        }
    }
}
  • Pros : one close, one possible exception, no flush needed (for output streams)
  • Cons : still inelegant : null dance, one must be careful in the order of the ifs, no way to generalize

So question still stands.



来源:https://stackoverflow.com/questions/16363642/java-6-io-wrapped-streams-closing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!