Odczyt i zapis do plików w Javie
Programy, które do tej pory pokazywaliśmy zawsze przetwarzały pewne dane natomiast natychmiast po zakończeniu ich wykonywania dane bezpowrotnie przepadały. Jednym ze sposobów utrwalenia wyników działania aplikacji jest zapis do plików. Możemy również wykorzystać je jako źródło danych do przetworzenia w programie. Java udostępnia narzędzia niezbędne do obu tych czynności. Gdy danych jest zwyczajnie dużo dobrym pomysłem może się okazać użycie baz danych. W poprzedniej części przyjrzeliśmy się optymalizacji łańcuchów znakowych przez klasę StringBuilder.
Czym jest plik?
W najprostszej definicji plik to uporządkowany ciąg bajtów. Jednak na dysku ze względu ułożenie innych danych może zostać pofragmentowany. Ważne jednak, aby zrozumieć, że dla systemu plik jest logiczną całością. W związku z tym czytając np. plik linia po linii nie musimy patrzeć na jego fizyczne położenie na nośniku.
Ścieżka folderów
Kolejnym ważnym elementem są katalogi, które służą do porządkowania plików. Aby dostać się do konkretnego pliku należy najpierw wskazać ścieżkę, którą tworzą kolejne nazwy katalogów. W zależności od systemu oddzielone są innymi separatorami. W przypadku systemów Unix są to ukośniki /, a Windows odwrotne ukośniki \.
Właśnie ukośniki w systemach Windows mogą powodować problemy, gdyż są również wykorzystywane przy symbolach zastępczych. Wspominaliśmy o tym już na samym początku szkolenia.
Przykładowa ścieżka w systemie Unix może wyglądać następująco.
1 |
/home/user/plik.txt |
W przypadku systemów Windows.
1 |
C:\Users\username\Documents\plik.txt |
Aby prawidłowo zapisać tę ścieżkę w Javie musimy podwoić znak \\.
1 |
String path = "C:\\Users\\username\\Documents\\plik.txt" |
Klasa Files
Java oferuje wiele klas, które umożliwiają dostęp do plików. Od początku istnienia języka istnieje klasa File
, która oferuje wiele przydatnych metod do obsługi plików. Od Javy w wersji 7 twórcy dodali nową klasę Files
dostarczającą szeregu metod statycznych, które jeszcze bardziej upraszczają obsługę plików.
Odczyt z pliku w Javie
Na początek przyjmijmy, że pliki do odczytu będą relatywnie małe. Będą zawierały maksymalnie kilka kB, aby nie przejmować się np. zbyt małą ilością pamięci potrzebną, aby wczytać plik w całości.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package pl.programistajava.files; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; public class FileTest { public static void main(String[] args) { try { List<String> file = Files.readAllLines(Paths.get("D:\\EclipseWorkspace\\TEST\\src\\plik.txt")); file.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } } } |
Powyższy kod zapisuje całą zawartość pliku określonego w ścieżce do listy. Każda linia w pliku znajduje się w osobnym elemencie. Ponieważ jest interfejs List implementuje interfejs Iterable
to możliwe jest użycie metody domyślnej forEach()
, która pozwala np. na wyświetlenie wszystkich elementów na ekranie.
Korzystając ze starszej implementacji kod wyglądałby następująco.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package pl.programistajava.files; import java.io.File; import java.io.IOException; import java.util.Scanner; public class FileTest { public static void main(String[] args) { try { File file = new File("D:\\EclipseWorkspace\\TEST\\src\\plik.txt"); Scanner sc = new Scanner(file); while (sc.hasNextLine()) System.out.println(sc.nextLine()); sc.close(); } catch (IOException e) { e.printStackTrace(); } } } |
W tym przypadku potrzebujemy dodatkowo klasę Scanner
. Na koniec należy zawsze pamiętać o zamknięciu obiektu metodą close()
.
Zapis do pliku w Javie
Do wykonania zapisu również wykorzystamy klasę Files
. Jeżeli podamy dwa argumenty czyli ścieżkę do pliku oraz tablicę bajtów do zapełnienia, to plik zostanie w całości nadpisany. Możliwe jest jednak podanie trzeciego argumentu, który implementuje interfejs OpenOption
np. typ Enum
– StandardOpenOption
.
Użycie jego pozwala na decyzję czy chcemy nadpisywać cały plik od początku, czy też dopisywać treść do istniejącej już zawartości.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package pl.programistajava.files; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; public class FileTest { public static void main(String[] args) { try { byte[] strToBytes = "Witamy na kursie programistajava.pl".getBytes(); Files.write(Paths.get("D:\\EclipseWorkspace\\TEST\\src\\plik.txt"), strToBytes); } catch (IOException e) { e.printStackTrace(); } } } |
Zwróćmy uwagę na to, że metoda write()
nie zapisuje bezpośrednio obiektu typu String
. Musimy najpierw zamienić go na tablicę bajtów, a dopiero potem można umieścić go jako argument funkcji. Aby zamienić String na ciąg bajtów należy użyć metody getBytes()
.
W następnej części poznamy bliżej klasę Arrays oraz metody, które oferuje.