7

Wszystko,Jak zamknąć plik po wychwyceniu wyjątku IOException w java?

Staram się upewnić, że plik mam otwarte z BufferedReader jest zamknięty, kiedy złapać IOException, ale wydaje się, jakby mój obiekt BufferedReader jest poza zakresem w bloku catch.

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList) 
{ 
    fileArrayList.removeAll(fileArrayList); 

    try { 
     //open the file for reading 
     BufferedReader fileIn = new BufferedReader(new FileReader(fileName)); 

     // add line by line to array list, until end of file is reached 
     // when buffered reader returns null (todo). 
     while(true){ 
       fileArrayList.add(fileIn.readLine()); 
      } 
    }catch(IOException e){ 
     fileArrayList.removeAll(fileArrayList); 
     fileIn.close(); 
     return fileArrayList; //returned empty. Dealt with in calling code. 
    } 
} 

Netbeans narzeka, że ​​„nie można odnaleźć symbol fileIn” w bloku catch, ale chcę, aby upewnić się, że w przypadku IOException że czytelnik zostaje zamknięty. Jak mogę to zrobić bez brzydoty drugiej konstrukcji try/catch wokół pierwszej?

Wszelkie porady lub wskazówki co do najlepszych praktyk w tej sytuacji jest ceniona,

Odpowiedz

22
BufferedReader fileIn = null; 
try { 
     fileIn = new BufferedReader(new FileReader(filename)); 
     //etc. 
} catch(IOException e) { 
     fileArrayList.removeall(fileArrayList); 
} finally { 
    try { 
     if (fileIn != null) fileIn.close(); 
    } catch (IOException io) { 
     //log exception here 
    } 
} 
return fileArrayList; 

Kilka rzeczy o powyższym kodzie:

  • blisko powinny być w końcu, w przeciwnym razie nie zostanie zamknięty, gdy kod zakończy się normalnie, czy jest jakiś inny wyjątek wyrzucony poza wyjątek IOException.
  • Zazwyczaj masz statyczną metodę narzędzia do zamykania takiego zasobu, aby sprawdzał wartość zerową i przechwytywał wszystkie wyjątki (których nigdy nie chcesz robić poza logowaniem się w tym kontekście).
  • Zwrot należy po starcie, aby kod główny i wyjątek były zwracane bez nadmiarowości.
  • Jeśli umieścisz powrót wewnątrz, wygeneruje ostrzeżenie kompilatora.
+0

+1 dla "w końcu". Zaskakująco wiele odpowiedzi nie wspominało o tym. Oto kilka interesujących linków Sun: [Lekcja: Basic IO] (http://java.sun.com/docs/books/tutorial/essential/io/) i [Lesson: Exceptions] (http: //java.sun .com/docs/books/tutorial/essential/exceptions/index.html) – BalusC

+0

Możesz usunąć zaznaczenie 'null' i przechwycić' Exception', chyba że masz zamiar poinformować użytkownika, że ​​nie można zamknąć pliku w porównaniu do cann otwórz to. Ale generalnie użytkownicy nie dbają o to. –

+0

Zamknąłeś BufferdedRead, ale nie FileReader? –

0

Move deklaracja z bloku try:

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList) 
{ 
    fileArrayList.removeAll(fileArrayList); 

    BufferedReader fileIn = null; 
    try { 
     //open the file for reading 
     fileIn = new BufferedReader(new FileReader(fileName)); 

     // add line by line to array list, until end of file is reached 
     // when buffered reader returns null (todo). 
     while(true){ 
       fileArrayList.add(fileIn.readLine()); 
      } 
    }catch(IOException e){ 
     fileArrayList.removeAll(fileArrayList); 
     fileIn.close(); 
     return fileArrayList; //returned empty. Dealt with in calling code. 
    } 
} 

Ale to musisz uważać, że fileIn faktycznie zainicjowana przed próbuje go zamknąć:

if (fileIn != null) 
    fileIn.close(); 
+0

Jeśli istnieje wyjątek w konstruktorach czytnika (na przykład plik nie został znaleziony), zostanie on zdmuchnięty za pomocą 'NullPointerException'. Musisz sprawdzić 'null' w' catch'. –

+1

W twoim haczyku masz 'fileIn.close();', który również rzuca wyjątek IOException. Kompilator na to nie pozwoli. –

1

po trafieniu bloku catch, wszelkie zmienne zadeklarowane w próbie nie są scoped więcej. Deklaracja BufferedReader fileIn = null; powyżej bloku try, a następnie przypisz go do środka. W swoim bloku catch wykonaj (fileIn! = Null) fileIn.close();

1

Narzeka, że ​​symbol nie istnieje, ponieważ tak nie jest. Jest w bloku try. Jeśli chcesz odwołać się do fileIn, musisz zadeklarować go poza próbą.

Jednak naprawdę brzmi to tak, jakbyś chciał umieścić zakończenie w bloku finally: powinieneś zamknąć plik bez względu na sukces lub porażkę przed powrotem.

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList) 
{ 
    fileArrayList.removeAll(fileArrayList); 

    BufferedReader fileIn = null; 
    try { 
     //open the file for reading 
     fileIn = new BufferedReader(new FileReader(fileName)); 

     // add line by line to array list, until end of file is reached 
     // when buffered reader returns null (todo). 
     while(true){ 
       fileArrayList.add(fileIn.readLine()); 
      } 
    }catch(IOException e){ 
     fileArrayList.removeAll(fileArrayList); 
    }finally{ 
     if(fileIn != null) fileIn.close(); 
    } 
    return fileArrayList; 
} 
0

Zadeklaruj BufferedReader poza blokiem try i ustaw go na wartość null, a następnie użyj bloku finally, aby go zamknąć, jeśli nie jest pusty. Również fileArrayList jest przekazywane przez referencję, więc wszelkie wprowadzone w nim zmiany będą miały miejsce w przypadku obiektu, który przekazałeś, więc nie ma potrzeby go również zwracać.

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList) 
{ 
    fileArrayList.removeAll(fileArrayList); 
    BufferedReader fileIn = null; 
    try { 
     //open the file for reading 
     fileIn = new BufferedReader(new FileReader(fileName)); 

     // add line by line to array list, until end of file is reached 
     // when buffered reader returns null (todo). 
     while(true){ 
       fileArrayList.add(fileIn.readLine()); 
      } 
    }catch(IOException e){ 
     fileArrayList.removeAll(fileArrayList); 
    }finally 
    { 
     try 
     { 
      if(fillIn != null) 
       fileIn.close(); 
     } 
     catch(IOException e){} 
    } 
    return fileArrayList; //returned empty. Dealt with in calling code. 
} 
1

Mój preferowany sposób wykonywania Clean-up po drodze wyjątku (gdy clean-up może potencjalnie również wyjątek) jest umieścić kod w bloku try wewnątrz innego try/finally bloku, co następuje:

public static ArrayList readFiletoArrayList(String fileName, ArrayList fileArrayList) { 
    fileArrayList.removeAll(fileArrayList); 

    try { 
     //open the file for reading 
     BufferedReader fileIn = null; 

     try { 
      fileIn = new BufferedReader(new FileReader(fileName)); 
      // add line by line to array list, until end of file is reached 
      // when buffered reader returns null (todo). 
      while(true){ 
       fileArrayList.add(fileIn.readLine()); 
      } 
     } finally { 
      if (fileIn != null) { 
       fileIn.close(); 
      } 
     } 
    }catch(IOException e){ 
     fileArrayList.removeAll(fileArrayList); 
     return fileArrayList; //returned empty. Dealt with in calling code. 
    } 
} 
+0

Ma to tę wadę, że połknie niewłaściwy wyjątek. Jeśli readLine zawiedzie z jakiegoś powodu, generuje wyjątek IOException. Plik jest następnie zamknięty w końcu. Jeśli zamknięcie pliku również się nie powiedzie, zostanie zgłoszony nowy wyjątek IOException, a pierwszy wyjątek, z potencjalnie wartościowym komunikatem o błędzie, zostanie utracony. –

0

lepiej nie radzić sobie z null - the general idiom for resource acquisition and release in Java is:

final Resource resource = acquire(); 
try { use(resource); } 
finally { resource.release(); } 

tak:

public static List<String> readFiletoArrayList(String fileName, 
     List<String> fileArrayList, String charsetName) { 
    fileArrayList.clear(); // why fileArrayList.removeAll(fileArrayList) ? 
    try { 
     InputStream file = new FileInputStream(fileName); 
     try { 
      InputStreamReader reader = new InputStreamReader(file, charsetName); 
      BufferedReader buffer = new BufferedReader(reader); 
      for (String line = buffer.readLine(); line != null; line = buffer 
        .readLine()) { 
       fileArrayList.add(line); 
      } 
     } finally { 
      try { 
       file.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); // you do not want this to hide an 
       // exception thrown earlier so swallow it 
      } 
     } 
    } catch (IOException e) { 
     fileArrayList.clear(); // returned empty. Dealt with in client 
    } 
    return fileArrayList; 
} 

Zobacz moje punkty here

Jeśli używasz Reader moszczu określić kodowanie jak robię tutaj. Jeśli chcesz przeczytać bajty, zapomnij o czytniku. Również jeśli używasz readLine(), musisz zapomnieć o znakach końca linii - jeśli to jest problem, rozważ całkowite pominięcie BufferedReader.

+0

Wydaje mi się, że gdyby plik był otwarty do zapisu, a nie do czytania, bezpieczna operacja wymagałaby, aby każdy wyjątek IOException, który występuje podczas zamykania pliku, nie został połknięty, chyba że istniał już wyjątek IOException, który wywoływał stos wywołań. Może być rozsądnie połknąć 'wyjątek IOEx' wyrzucony przez operację zamykania pliku, która sama jest w' Catch (IOException e) ', ale jeśli' finally' zostanie osiągnięty poprzez normalne wykonanie kodu, połknięcie 'IOException' na close może spowodować, że osoba dzwoniąca błędnie uwierzyła, że ​​plik został zapisany, gdy tak naprawdę nie był. – supercat

+0

@supercat: masz rację - ale to jest czytanie pliku. Pisanie musi opróżnić dekorator (i nie polegać na zamknięciu) - _if jest dekorator_. Przechodzę przez pewne osobliwości [tutaj] (http://stackoverflow.com/questions/16363642/java-6-io-wrapped-streams-closing) - niesłusznie zamknięte –

+1

Wzorzec dusi wyjątków oczyszczania jest często stosowany bez względu na to, co oczyszczenie pociąga za sobą. W niektórych przypadkach jest w porządku, ale jako nawyk wydaje się niebezpieczny. Jeśli chodzi o powiązane (zamknięte) pytanie, sugeruję, aby zacząć od nieco mniejszej "historii". To, co naprawdę chcesz wiedzieć (z tego, co potrafię powiedzieć), to jak sobie poradzić z wyjątkiem wyrzuconym z konstruktora, który ma przejąć własność, jeśli przekazany strumień. Moja sugestia byłaby taka, że ​​takie konstruktory powinny zamknąć przekazywany strumień, jeśli rzucają wyjątek, lub być zawinięte w metodę fabryczną, która to robi. – supercat

Powiązane problemy