简体   繁体   中英

Why not open the stream after the close?

In the method getFileName() created the object BufferedReader and assigned reference to the object to the variable - reader. Then stream closed in the finally.

Then invoked the method readStringsFromConsole(). There creates the same object. But thrown IOException. Why did it happen ?

ps: sorry for my English :)

stacktrace:

java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:170)
at java.io.BufferedInputStream.read(BufferedInputStream.java:336)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.test.home04.Solution.readStringsFromConsole(Solution.java:55)

code:

import java.io.*;
import java.util.*;
public class Solution
{
   public static void main(String[] args)
   {
    String fileName = getFileName();
    ArrayList<String> listStrings = readStringsFromConsole();
    writeToFileFromList(fileName, listStrings);
}

public static void writeToFileFromList (String fileName, ArrayList<String> listInputString)
{
    PrintWriter writer = null;

    try {
        writer = new PrintWriter(fileName, "UTF-8");
        for (String stringItem : listInputString)
            writer.write(stringItem);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (writer != null)
                writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static ArrayList<String> readStringsFromConsole() {
    BufferedReader reader = null;
    ArrayList<String> listInputString = new ArrayList<String>();
    String line = null;

    try {
        reader = new BufferedReader(new InputStreamReader(System.in));
        while (true)
        {
            line = reader.readLine();
            if ("exit".equals(line))
                break;
            listInputString.add(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (reader != null)
                reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return listInputString;
    }
}

public static String getFileName()
{
    BufferedReader reader = null;
    String fileName = null;
    try {
        reader = new BufferedReader(new InputStreamReader(System.in));
        while (fileName == null) {
            fileName = reader.readLine();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (reader != null)
                reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileName;
    }
}
}

If you create a reader from System.in and close it, it also closes System.in , which can't be opened again even if you create another reader.

In short - don't close readers which are created from System.in .

Also as Andreas pointed out in the comment, the general guideline should be that System.in should only ever be wrapped once in the lifetime of the command-line program (whether by Scanner , BufferedReader , or something else), and it should never be closed. The wrapping should likely occur at the beginning of main() , and the wrapper object should either be passed around or stored in a field (static or instance).

Why did it happen ?

It happened because you closed System.in in your getFilename method.

Why not open the stream after the close?

Basically, because you can't, or if you are asking about the behavior of the JVM ... >>it<< can't.

When close() is called, the close gets sent to the operating system which closes and releases the underlying file descriptor. Once closed, the OS does not have enough information to reopen the previous file. And if the file descriptor was for an (unnamed) pipe or socket stream, then the connection cannot be remade because:

  • the application or service at the other end will typically have gone away,

  • in the case of a TCP/IP socket, the protocol does not allow reconnection.

In short: don't close a stream if you need to read or write more from / to it later, and avoid closing System.{in,out,err} entirely.


Now if your application had a filename or a host / port, it could open a new FileReader or connect a new socket. But in the case of the System.* streams, that information is not available to the application (or the JVM).


But in your particular case, I suspect that your intention is that getFileName returns the filenames supplied one at a time; ie each call returns the next filename. If that is the case, you will have to implement it differently:

  • It shouldn't close the stream or the reader.

  • It shouldn't open the reader (probably).

  • It should return the first (or next) line that it reads rather than reading all lines and returning the last one, as it currently does.

You are closing the stream from System.in. Closed stream needs to be opened before reusing it. Don't close them if you create them from System.in. Try this,

import java.io.*;
import java.util.*;
public class Solution
{

public static void main(String[] args)
{
    String fileName = getFileName();
    ArrayList<String> listStrings = readStringsFromConsole();
    writeToFileFromList(fileName, listStrings);
}

public static void writeToFileFromList (String fileName, ArrayList<String> listInputString)
{
    PrintWriter writer = null;

    try {
        writer = new PrintWriter(fileName, "UTF-8");
        for (String stringItem : listInputString)
            writer.write(stringItem);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (writer != null)
                writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static ArrayList<String> readStringsFromConsole() {
    BufferedReader reader = null;
    ArrayList<String> listInputString = new ArrayList<String>();
    String line = null;

    try {
        reader = new BufferedReader(new InputStreamReader(System.in));
        while (true)
        {
            line = reader.readLine();
            if ("exit".equals(line)) {
                break;
        }
            listInputString.add(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (reader != null)
                //do not close the stream
                //reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return listInputString;
    }
}

public static String getFileName()
{
    BufferedReader reader = null;
    String fileName = null;
    try {
        reader = new BufferedReader(new InputStreamReader(System.in));
        while (fileName == null) {
        System.out.println("Enter a file name: ");
            fileName = reader.readLine();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (reader != null)
                //do not close the stream
                //reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileName;
    }
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM