I_R_W13_M12_Java Działania na plikach w języku Java
Porównaj swoje rozwiązanie z rozwiązaniem podobnego problemu przedstawionym w filmie.

Film dostępny pod adresem /preview/resource/R12lWh6BwGnAE
Film nawiązujący do treści materiału dotyczącej zapisu i odczytu z pliku w języku Java.
Teraz dokładniej omówimy wykorzystane tam metody odczytywania i zapisywania danych do pliku oraz pokażemy inne sposoby pozwalające na osiągnięcie takiego samego efektu. Przedstawione tu metody pozwolą na zapoznanie się zarówno z obsługą plików tekstowych, jak i obsługą danych zapisywanych i odczytywanych bajtami.
Zapisywanie informacji w nowym pliku
Do zapisu danych w pliku możemy wykorzystać przedstawioną w poprzedniej sekcji klasę FileWriter. Jest to klasa służąca do zapisywania danych tekstowych w domyślnym kodowaniu znaków systemu operacyjnego (np. UTF‑8 dla systemu Windows).
Użycie klasy wymaga utworzenia obiektu z wykorzystaniem konstruktora, który jako pierwszy argument przyjmuje ścieżkę do pliku. Jeżeli jako drugi opcjonalny argument podamy wartość true, dane będzie można dopisywać na końcu pliku. Jeżeli nie podajemy drugiego argumentu lub kiedy podamy wartość false, dane zapisywane w pliku zastępują dotychczasową zawartość.
Przykłady ścieżki do pliku:
w systemie Windows:
C:\\Dane\\plik.txt,w systemie Linux:
/home/uzytkownik/dane/plik.txt.
Odwołując się do danej lokalizacji w języku Java, używamy podwójnych ukośników dla języka Windows. Wynika to z tego, że pojedynczy ukośnik jest traktowany jako znak specjalny.
Jeżeli program i odczytywany plik znajdują się w tym samym katalogu, ścieżkę ograniczamy tylko do nazwy pliku.
Omawiany obiekt typu FileWriter można również utworzyć, przekazując do konstruktora obiekt klasy File:
Do zapisu danych przy użyciu obiektu typu FileWriter służy metoda write(). Jako argumenty przyjmuje wartość tekstową.
Po zakończeniu korzystania z obiektu, należy zamknąć strumień wyjścia przy użyciu metody close().
Do zapisywania danych tekstowych do pliku służy również klasa BufferedWriter. Różni się ona od klasy FileWriter możliwością buforowania znaków w celu wydajniejszego zapisywania znaków, ich ciągów i tablic.
Podobnie jak w przypadku klasy FileWriter, by wykorzystać klasę BufferedWriter do zapisu danych do pliku, musimy utworzyć obiekt tej klasy. Konstruktor klasy jako argument przyjmuje obiekt klasy FileWriter, któremu podajemy ścieżkę do pliku.
Aby zapisać dane do pliku z wykorzystaniem obiektu klasy BufferedWriter, wykorzystujemy metodę write(), która zapisuje do pliku podany jej jako argument znak lub ciąg znaków (jeżeli chcemy zapisać dane innego typu, najpierw należy je przekonwertować do typu tekstowego).
Podobnie jak w poprzednim wypadku, otwarty strumień wyjścia należy zamknąć po zakończeniu korzystania z niego za pomocą wywołania metody close() na obiekcie klasy BufferedWriter.
Ostatnią klasą służącą do zapisywania danych do pliku, którą omówimy, będzie klasa FileOutputStream. Podobnie jak w wypadku innych klas, na początku musimy utworzyć jej obiekt. Konstruktor jako argument przyjmuje obiekt klasy File reprezentujący plik, do którego chcemy zapisywać dane.
Tak jak we wcześniej omówionych klasach, tutaj również metodą służącą do zapisu danych do pliku jest metoda write(). Klasa ta różni się jednak od poprzednich tym, że operuje na bajtach, nie na danych tekstowych. Musimy zatem pamiętać, by dane do zapisania przekonwertować na bajty (często jest do tego wykorzystywana metoda getBytes()).
Po zakończeniu pracy na strumieniu wyjścia należy go zamknąć za pomocą metody close().
Dopisywanie informacji do pliku
Czasami nie chcemy tworzyć nowego pliku, a dodać informacje do już istniejącego. W takiej sytuacji postępujemy podobnie jak w dotychczas przestawionych przykładach – zmieniamy tylko sposób wywołania konstruktora klasy FileWriter. Przyjmuje on dodatkowy argument w postaci wartości logicznej true, która sygnalizuje, że do otwartego w ten sposób pliku będziemy dopisywać nową treść przy zachowaniu jego oryginalnej zawartości. Nowe dane dopisywane są na końcu pliku.
Poniżej przykłady użycia omawianych wcześniej klas:
Do dopisywania danych używamy stosowanej już wcześniej metody write(), natomiast aby zamknąć wykorzystany strumień, przywołujemy metodę close().
Odczytywanie danych z pliku
Gdy piszemy program analizujący duże ilości danych, nie wprowadzamy ich zazwyczaj za pomocą klawiatury. Tak czasochłonny proces warto przyspieszyć, wczytując informacje z pliku tekstowego.
W języku Java mamy do dyspozycji wiele metod umożliwiających odczytanie danych z pliku. Omówimy tutaj cztery z nich.
Pierwszy sposób wymaga użycia klasy FileReader. Podobnie jak w przypadku operacji zapisu, najpierw musimy utworzyć obiekt klasy FileReader. Jako argument konstruktora podajemy ścieżkę do pliku, który chcemy odczytać.
Do odczytywania pojedynczych znaków służy metoda read(), która zwraca wartość typu całkowitego. Wartość tę trzeba przekonwertować na typ tekstowy, aby otrzymać odczytany znak. Metoda zwraca wartość , jeżeli odczytano wszystkie dane. Dzięki czemu użyta w pętli pozwala odczytać wszystkie znaki z pliku. Choć jest to możliwe, omawiana metoda nie jest zalecana do odczytywania liczb z plików tekstowych.
Po wykorzystaniu obiektu FileReader strumień wejścia zamykamy za pomocą metody close().
Innym sposobem odczytywania z pliku jest wykorzystanie klasy BufferedReader. Przy tworzeniu obiektu tej klasy jako argument do jej konstruktora podajemy obiekt typu FileReader.
Klasa ta pozwala na odczytanie całego wiersza danych tekstowych z podanego pliku za pomocą metody readLine() (zwróci wartość null w przypadku braku wartości do odczytu). Po odczytaniu danych strumień wejścia zamykamy.
Kolejny sposób odczytywania danych z plików, który został wykorzystany w sekcji multimedialnej, polega na użyciu klasy Scanner. Podczas tworzenia obiektu tej klasy wymagane jest podanie konstruktorowi obiektu typu File wskazującego plik, z którego chcemy skorzystać.
Klasa Scanner posiada kilka metod, które zazwyczaj wykorzystuje się w pętli:
next()– odczytuje z pliku nieprzerwany ciąg znaków aż do napotkania znaku spacji, tabulacji lub końca linii,nextInt()– pozwala na odczytanie ciągu znaków jako liczby całkowitej aż do napotkania znaku spacji, tabulacji lub końca linii,nextLine()– umożliwia odczytanie całego wiersza pliku.
Do odczytywania kolejnych nieprzerwanych ciągów znaków z pliku, np. wyrazów, użyjemy kodu:
Aby odczytać kolejne liczby całkowite z pliku, zastosujemy zapis:
Natomiast fragment kodu odpowiedzialny za odczytanie kolejnych wierszy prezentuje się następująco:
Po odczytaniu danych strumień wejścia zamykamy:
Ostatnią klasą umożliwiającą odczytanie danych z pliku, którą tu omówimy, jest klasa FileInputStream pozwalająca na odczytanie danych bajtowych. Jej konstruktor przyjmuje jako parametr obiekt klasy File. Może ona być użyta m.in. do odczytania danych zapisanych do pliku za pomocą klasy FileOutputStream.
Klasa ta przeznaczona jest do odczytu nieprzetworzonych bajtów, takich jak np. dane obrazu. Nie jest zalecana do odczytywania plików tekstowych. Do czytania pojedynczych bajtów stosuje się metodę read(), która zwraca wartość całkowitą z zakresu lub wartość , kiedy osiągnie koniec pliku.
Po zakończeniu odczytywania danych strumień wejściowy należy zamknąć.
Program wypisze zawartość podanego pliku w postaci liczb całkowitych z zakresu , ponieważ taki zakres wartości można zapisać w jednym bajcie.
Wypisywane liczby można zamieniać na znaki: System.out.print((char)bajt); – traktując je jako kody ASCII. Jeżeli odczytywany plik zawiera tekst zapisany tylko za pomocą znaków alfanumerycznych z tabeli ASCII, na wyjściu zobaczymy jego zawartość. W pozostałych przypadkach również zobaczymy ciąg znaków z tabeli ASCII, ale niebędący komunikatywnym tekstem.
Przed użyciem omówionych klas pamiętajmy o ich zaimportowaniu. Klasę Scanner importujemy z pakietu java.util, wszystkie pozostałe z pakietu java.io.
Słownik
szablon, na podstawie którego tworzymy obiekty; zawiera definicję właściwości (zmiennych) i działań (funkcji zwanych metodami) obiektu
plik, który przechowuje ciąg znaków zapisany według wybranego kodowania