2015-10-14 75 views
0

在方法getFileName()中创建对象BufferedReader并将对象的引用分配给变量reader。然后流在终于关闭。关闭后为何不打开流?

然后调用方法readStringsFromConsole()。有创建相同的对象。但抛出IOException。为什么发生?

PS:对不起,我的英语:)

堆栈跟踪:

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) 

代码:

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; 
    } 
} 
} 
+0

封闭的流不能重新打开。您必须在每次完全读完文件时使用新的FileInputStream或FileReader重新打开该文件 – ControlAltDel

回答

4

如果从System.in创建一个阅读器和关闭它,它也会关闭System.in,即使您创建另一个阅读器,也无法再打开它。

总之 - 不要关闭从System.in创建的读者。

另外,作为安德烈亚斯在评论中指出,一般的指导原则应该是System.in应该永远只能一次在命令行程序的生命周期包(无论是通过ScannerBufferedReader,或别的东西),并应永远不会关闭。包装应该可能发生在main()的开头,并且包装器对象应该传递或存储在一个字段(静态或实例)中。

+0

也许添加此答案:一般指南应该是'System.in'应该只在命令的生命周期中被封装一次*在线程序(无论是'Scanner','BufferedReader'还是其他的),它都不应该被关闭。包装应该可能发生在'main'的开头,并且传递或存储在一个字段(静态或实例)中。 – Andreas

0

您正在关闭System.in中的流。封闭的流在重新使用之前需要打开。如果您从System.in创建它们,请不要关闭它们。 试试这个,

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

为什么会发生?

它发生是因为您在您的getFilename方法中关闭了System.in。

为什么在关闭后不打开流?

基本上,因为你不能,或者如果你问的是JVM的行为...... >>它< <不能。

当调用close()时,关闭被发送到操作系统,关闭并释放底层文件描述符。一旦关闭,操作系统没有足够的信息来重新打开前一个文件。如果文件描述符是一个(未命名)管道或流套接字,则连接不能重拍,因为:

  • 在另一端的应用程序或服务通常都走了,

  • 在TCP/IP套接字的情况下,该协议不允许重新连接。

简而言之:如果你需要读取或写入更多的从/到后来,避免关闭System.{in,out,err}完全不关闭流。


现在,如果你的应用程序有一个文件名或主机/端口,它可以打开一个新的FileReader或连接一个新的套接字。但是在System.*流的情况下,该信息不适用于应用程序(或JVM)。


但你的具体情况,我怀疑你的意图getFileName返回文件名提供一次一个;即每个呼叫返回下一个文件名。如果是这种情况,您必须以不同的方式实施:

  • 它不应该关闭流或读者。

  • 它不应该打开阅读器(可能)。

  • 它应该返回它读取的第一条(或下一条)行,而不是像现在这样读取所有行并返回最后一行。