BufferedReader未正确关闭

时间:2014-03-27 10:12:14

标签: java console bufferedreader

我正在开发一个名为ConsoleInput的类,它应该简化我正在开发的应用程序的控制台输入。在测试它时,我注意到我似乎无法关闭BufferedReader,并实例化一个新的ConsoleInput类。我可以在不关闭BufferedReader的情况下完成,但它仍然是一个有趣的问题。我想知道为什么我不能关闭它,以及我可以做些什么来改变它。

ConsoleInput类:

package frontend;

import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.io.*;

public class ConsoleInput {
    private BufferedReader buf = null;
    private boolean ignoreconfirm = false;
    private boolean confirmation = false;
    private boolean closed = false;
    private String dateformat = "yyyy-MM-dd";

    private boolean confirm(String value) throws IOException {
        boolean accept = false;
        boolean answer = false;
        String l = "I";

        while (!accept) {
            System.out.print(l + "s '" + value + "' correct (Y/N) ?: ");
            String line = buf.readLine();
            line = line.trim();
            line = line.toLowerCase();
            if (line.equals("y") || line.equals("yes")) {
                accept = true;
                answer = true;
            } else if (line.equals("n") || line.equals("no")) {
                accept = true;
                answer = false;
            }
            if (!accept) System.out.print("Try confirmation again, ");
            l.toLowerCase();
        }

        return answer;
    }

    public String getString() throws IOException, ExcConsoleInputClosed {
        if (closed) throw new ExcConsoleInputClosed();
        boolean accept = false;
        String line = null;

        while (!accept) {
            line = buf.readLine();
            if (confirmation && !ignoreconfirm) {
                accept = confirm(line);
                if (!accept) System.out.print("Try input again: ");
            } else {
                accept = true;
            }
        }

        return line;
    }

    public Integer getInt() throws IOException, ExcConsoleInputClosed {
        boolean accept = false;
        boolean parsed = false;
        Integer value = null;
        String input = null;

        while (!parsed) {
            if (confirmation) ignoreconfirm = true;
            input = getString();
            if (confirmation) ignoreconfirm = false;
            input.trim();

            if (confirmation) accept = confirm(input);
            else accept = true;
            if (!accept) System.out.print("Try input again: ");
            else {
                try {
                    value = new Integer(Integer.parseInt(input));
                    parsed = true;
                } catch (NumberFormatException e) {
                    System.out.print("Error parsing your input, try again: ");
                }   
            }
        }

        return value;
    }

    public Date getDate()
            throws IOException, ExcConsoleInputClosed {
        boolean accept = false;
        boolean parsed = false;
        Date value = null;
        String input = null;
        SimpleDateFormat format = new SimpleDateFormat(dateformat);

        while (!parsed) {
            if (confirmation) ignoreconfirm = true;
            input = getString();
            if (confirmation) ignoreconfirm = false;
            input.trim();

            if (input.equals("help")) {
                System.out.println("Enter a date with format " + dateformat + ".");
            } else {
                if (confirmation) accept = confirm(input);
                else accept = true;
                if (!accept) System.out.print("Try input again: ");
                else {
                    try {
                        value = format.parse(input);
                        parsed = true;
                    } catch (ParseException e) {
                        System.out.print("Error parsing your input, try again");
                    }
                }
            }
        }

        return value;
    }

    public void toggleConfirm() {
        confirmation = !confirmation;
    }

    public boolean confirmation() { return confirmation; }

    public void close() throws IOException {
        closed = true;
        buf.close();
    }

    public ConsoleInput() {
        buf = new BufferedReader(new InputStreamReader(System.in));
    }

}

此课程的单元测试:

public class feConsoleInput {
    public static void main(String[] args) {
        ConsoleInput console = new ConsoleInput();

        System.out.println("Fetching input from console.");
        for (int c=0; c <= 1; c++) {
            try {
                System.out.print("Enter a string: ");
                String text = console.getString();
                System.out.println("You entered: " + text);

                System.out.print("Enter a integer: ");
                Integer number = console.getInt();
                System.out.println("You entered: " + number);

                System.out.println("Enter a date...");
                Date date = console.getDate();
                System.out.println("You entered: " + date.toString());
                console.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExcConsoleInputClosed e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            System.out.println("");
            console = new ConsoleInput();
            console.toggleConfirm();
        }
    }
}

当它在关闭后第二次运行时,我得到了关闭Stream的IOException。据我所知,ConsoleInput类构造函数应该打开一个新构造函数。

Fetching input from console.
Enter a string: A string of input.
You entered: A string of input.
Enter a integer: 42
You entered: 42
Enter a date...
2012-12-07
You entered: Fri Dec 07 00:00:00 EST 2012
java.io.IOException: Stream closed
Enter a string: 

    at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:162)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:325)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:282)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:324)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:153)
    at java.io.BufferedReader.readLine(BufferedReader.java:316)
    at java.io.BufferedReader.readLine(BufferedReader.java:379)
    at frontend.ConsoleInput.getString(ConsoleInput.java:45)
    at test.feConsoleInput.main(feConsoleInput.java:17)

1 个答案:

答案 0 :(得分:2)

当您关闭BufferedInputStream时,它也会关闭基础System.in流。这无法撤消。

一个常见的解决方案是用CloseShieldInputStream包裹System.in以避免在关闭外部阅读器时将其关闭。

public ConsoleInput() {
    buf = new BufferedReader(new InputStreamReader(
            new CloseShieldInputStream(System.in)));
}

或者,只需在整个程序期间保持ConsoleInput课程的一个实例。