2015-10-14 53 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返回文件名提供一次一個;即每個呼叫返回下一個文件名。如果是這種情況,您必須以不同的方式實施:

  • 它不應該關閉流或讀者。

  • 它不應該打開閱讀器(可能)。

  • 它應該返回它讀取的第一條(或下一條)行,而不是像現在這樣讀取所有行並返回最後一行。