Odczyt tekstu z pliku

W języku Java dane z plików odczytujemy za pomocą odpowiednio skonstruowanej kompozycji klas reprezentujących tzw. strumienie danych. Klasy implementujące strumienie umieszczone są w pakiecie java.io biblioteki standardowej Java SE. Jeślibyśmy pokusili się teraz o przejrzenie dokumentacji pakietu java.io, to zobaczylibyśmy że jest tych klas kilkadziesiąt. Z pośród ich wszystkich będziemy używali tylko kilku, ale to nadal więcej niż mogłoby się wydawać potrzebne jak dla tak z pozoru prostego zadania. Ale zadanie to jest proste tylko z pozoru; inaczej odczytujemy przecież dane z pliku binarnego a inaczej z pliku tekstowego. Z pliku tekstowego dane możemy odczytywać znak po znaku, ale możemy też wybrać czytanie linia po linii. Znaki w pliku tekstowym mogą być zapisane z użyciem kodowania UTF-8, Windows-1250 albo dowolnego innego. Możliwości jest wiele, stąd też dostępne mechanizmy są nieco bardziej złożone niż moglibyśmy pierwotnie oczekiwać. Nie ma jedynej słusznej odpowiedzi na pytanie „jak odczytać tekst z pliku?”, ale oczywiście można podać kilka propozycji, w zależności od tego jakie są potrzeby i możliwości. Najprostrza metoda odczytująca tekst z pliku i wyświetlająca jego zawartość mogłaby wyglądać tak:

public void readFile(String filePath) throws IOException {
  FileReader fileReader = new FileReader(filePath);
  BufferedReader bufferedReader = new BufferedReader(fileReader);
  
  String textLine = bufferedReader.readLine();
  do {
    System.out.println(textLine);
  
    textLine = bufferedReader.readLine();
  } while(textLine != null);

  bufferedReader.close();
}

Metodę tę wywołujemy przekazując jako argument ścieżkę dostępu do pliku który chcemy odczytać, np. „C:/plik.txt”.

W pierwszej linii metody readFile(…) tworzymy strumień danych typu java.io.FileReader. Klasa FileReader służy do odczytu kolejnych znaków z pliku tekstowego zapisanego z użyciem domyślnego kodowania. Czytanie znak po znaku jest jednak niewygodne a do tego mało wydajne (operacje dyskowe są bardzo powolne), dlatego strumień fileReader typu FileReader opakowujemy w strumień typu java.io.BufferedReader. Klasa BufferedReader umożliwia odczytywanie tekstu liniami – udostępnia metodę readLine(), którą wywołujemy w kolejnej linii.

Metoda readLine() klasy java.io.BufferedReader zwraca obiekt typu String reprezentujący odczytaną linię tekstu albo wartość null jeśli nie ma już danych do odczytania, tj. jeśli dotarliśmy do końca pliku.

W pętli DO-WHILE odczytujemy następnie kolejne linie z pliku i wyświetlamy je na konsoli systemowej. Na końcu metody readFile(…) zamykamy strumień danych wywołując na nim metodę close(). Wywołanie metody close() powoduje zwolnienie zasobów systemowych związanych z tym strumieniem.

Metoda readFile(…) najprawdopodobniej zadziała gdy ją wywołamy, jednak jest to implementacja niedoskonała. Przede wszystkim brakuje obsługi wyjątków. Konstruktor klasy FileReader który uruchamiamy w pierwszej linii może rzucić wyjątek java.io.FileNotFoundException. Metody readLine() i close() mogą rzucić wyjątek java.io.IOException. Moglibyśmy poprzestać na zadeklarowaniu wyjątków w nagłówku metody (IOException jest nadklasą klasy FileNotFoundException więc wystarczy zadeklarować wyjątek IOException), tak jak to zrobiono w powyższym przykładzie, gdyby nie to, że zależy nam na tym aby wywołać metodę close().

Musimy wywołać metodę close() aby zwolnić zajęte zasoby systemowe, niezależnie od tego czy w trakcie odczytywania danych z pliku wystąpił wyjątek czy nie. Niezbędne minimum jakie powinniśmy zrobić w tym względzie to otoczyć wywołania metod readLine() i close() w klauzulę try i umieścić wywołanie metody close() w bloku finally. Nasza metoda powinna więc wyglądać następująco:

public void readFile(String filePath) throws IOException {
  FileReader fileReader = new FileReader(filePath);
  BufferedReader bufferedReader = new BufferedReader(fileReader);
  
  try {
    String textLine = bufferedReader.readLine();
    do {
      System.out.println(textLine);
  
      textLine = bufferedReader.readLine();
    } while (textLine != null);
  } finally {
    bufferedReader.close();
  }
}

Aby przypomnieć sobie sposób działania mechanizmu wyjątków wróćmy do serii artykułów poświęconej temu tematowi: „Wyjątki”, „Propagowanie wyjątków”, „Deklarowanie wyjątków” i „Obsługa wyjątków”.

0 0 votes
Daj ocenę
Subscribe
Powiadom o
guest

1 Komentarz
najstarszy
najnowszy oceniany
Inline Feedbacks
View all comments