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”.
Literówka w pierwszym akapicie. NajprostRzy –> Najprostszy 🙂
Pozdrawiam