Odczyt i zapis plików tekstowych
- Pliki i katalogi
- poziom: początkujący
- aktualizacja: 15 sierpnia 2026
Klasa Files z pakietu java.nio.file zastąpiła stare FileReader i BufferedWriter — jedna linijka robi to, co kiedyś zajmowało dziesięć. Pułapką jest kodowanie, choć nie takie, jak się zwykle powtarza: metody Files bez argumentu Charset same używają UTF-8, ale FileReader, FileWriter i Scanner aż do Javy 17 brały domyślne kodowanie systemu — i to przez nie plik zapisany na Windowsie pokazuje na Linuksie krzaczki. Dlatego w każdej metodzie poniżej StandardCharsets.UTF_8 jest podane wprost: widać, w jakim kodowaniu pracujesz, i nie zależysz od ustawień maszyny.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.stream.Stream;
/**
* Odczyt i zapis plików tekstowych — skryptyJAVA.pl
* Zapisz jako: PlikiTekstowe.java
*/
public class PlikiTekstowe {
/**
* Zapisuje tekst do pliku w UTF-8, nadpisując dotychczasową zawartość.
* Brakujące katalogi nadrzędne tworzy automatycznie.
*/
public static void zapisz(Path plik, String tresc) throws IOException {
utworzKatalogNadrzedny(plik);
Files.writeString(plik, tresc, StandardCharsets.UTF_8);
}
/** Dopisuje tekst na końcu pliku; jeśli pliku jeszcze nie ma, tworzy go. */
public static void dopisz(Path plik, String tresc) throws IOException {
utworzKatalogNadrzedny(plik);
Files.writeString(plik, tresc, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
/** Wczytuje cały plik do jednego napisu — wygodne dla plików do kilku megabajtów. */
public static String czytajCalosc(Path plik) throws IOException {
return Files.readString(plik, StandardCharsets.UTF_8);
}
/** Wczytuje plik linia po linii do listy; znaki końca linii nie trafiają do wyniku. */
public static List<String> czytajLinie(Path plik) throws IOException {
return Files.readAllLines(plik, StandardCharsets.UTF_8);
}
/**
* Liczy linie zawierające podany fragment, czytając plik strumieniowo.
* Nie wczytuje całości do pamięci, więc obsłuży plik większy niż dostępna sterta.
* Uwaga: strumień dekoduje leniwie, więc plik w innym kodowaniu niż UTF-8 zgłosi
* nieobsługiwany UncheckedIOException, a nie IOException zadeklarowany w sygnaturze.
*/
public static long policzLinieZawierajace(Path plik, String fragment) throws IOException {
try (Stream<String> linie = Files.lines(plik, StandardCharsets.UTF_8)) {
return linie.filter(linia -> linia.contains(fragment)).count();
}
}
/** Sprawdza, czy ścieżka wskazuje na istniejący zwykły plik (nie katalog). */
public static boolean istnieje(Path plik) {
return Files.isRegularFile(plik);
}
/** Zwraca rozmiar pliku w bajtach albo -1, gdy plik nie istnieje. */
public static long rozmiar(Path plik) throws IOException {
try {
return Files.size(plik);
} catch (NoSuchFileException brakPliku) {
return -1L;
}
}
/** Kopiuje plik, nadpisując cel, jeśli już istnieje. */
public static void kopiuj(Path zrodlo, Path cel) throws IOException {
utworzKatalogNadrzedny(cel);
Files.copy(zrodlo, cel, StandardCopyOption.REPLACE_EXISTING);
}
/** Usuwa plik. Zwraca true, gdy plik faktycznie istniał i został usunięty. */
public static boolean usun(Path plik) throws IOException {
return Files.deleteIfExists(plik);
}
/** Tworzy katalog nadrzędny wskazanego pliku, jeśli jeszcze go nie ma. */
private static void utworzKatalogNadrzedny(Path plik) throws IOException {
Path katalog = plik.getParent();
if (katalog != null) {
Files.createDirectories(katalog);
}
}
// ── PRZYKŁADY ───────────────────────────────────────────
public static void main(String[] args) throws IOException {
Path katalog = Files.createTempDirectory("demo-pliki-");
Path notatki = katalog.resolve("notatki.txt");
Path kopia = katalog.resolve("archiwum/notatki-kopia.txt");
try {
zapisz(notatki, "Pierwsza linia\nDruga linia z żółwiem\n"); // nadpisuje plik
dopisz(notatki, "Trzecia linia\n"); // dokleja na końcu
dopisz(notatki, "Czwarta linia z żółwiem\n");
System.out.println("Plik istnieje: " + istnieje(notatki));
System.out.println("Rozmiar: " + rozmiar(notatki) + " B");
System.out.println("--- cała treść ---");
System.out.print(czytajCalosc(notatki));
System.out.println("------------------");
List<String> linie = czytajLinie(notatki);
System.out.println("Liczba linii: " + linie.size());
System.out.println("Ostatnia linia: " + linie.get(linie.size() - 1));
System.out.println("Linii z 'żółwiem': " + policzLinieZawierajace(notatki, "żółwiem"));
kopiuj(notatki, kopia);
System.out.println("Kopia w: " + kopia);
System.out.println("Kopia ma ten sam rozmiar: " + (rozmiar(kopia) == rozmiar(notatki)));
} catch (IOException wyjatek) {
System.err.println("Błąd operacji na pliku: " + wyjatek.getMessage());
} finally {
// Sprzątanie po demonstracji — katalog usuwamy dopiero, gdy jest pusty
try {
System.out.println("Usunięto notatki: " + usun(notatki));
System.out.println("Usunięto kopię: " + usun(kopia));
Files.deleteIfExists(kopia.getParent());
Files.deleteIfExists(katalog);
} catch (IOException wyjatek) {
System.err.println("Nie udało się posprzątać: " + wyjatek.getMessage());
}
}
}
}
Jak użyć tego skryptu
- Skopiuj kod i zapisz go w pliku o nazwie
PlikiTekstowe.java— takiej samej jak nazwa klasy publicznej — a następnie uruchom go poleceniemjava PlikiTekstowe.java. Demonstracja pracuje w katalogu tymczasowym systemu i na końcu sama po sobie sprząta, więc niczego nie zaśmieci. - We własnym projekcie skopiuj potrzebne metody do swojej klasy narzędziowej. Ścieżkę zbudujesz przez
Path.of("dane", "raport.txt")albokatalog.resolve("raport.txt")— nie sklejaj ścieżek ręcznie ukośnikami. - Pamiętaj, że
zapisz(...)nadpisuje plik bez pytania, adopisz(...)dokleja tekst na końcu. Jeśli dopisujesz kolejne linie, sam dodaj na końcu każdej znak\n— metoda nie robi tego za ciebie. - Prawie każda metoda deklaruje
throws IOException— jedynym wyjątkiem jestistnieje(...)— więc wywołania musisz otoczyć blokiemtry/catchalbo przekazać wyjątek wyżej. Zobacz, jak zrobiono to wmain.
Warto wiedzieć
- Metody klasy
Filesbez argumentuCharsetzakładają UTF-8, aleFileReader,FileWriterczynew String(bajty)aż do Javy 17 brały domyślne kodowanie systemu. PodawajStandardCharsets.UTF_8wprost, a nie będziesz musiał pamiętać, która metoda należy do której grupy. readStringireadAllLineswczytują cały plik do pamięci — przy logu na kilkaset megabajtów dostanieszOutOfMemoryError. Wtedy czytaj strumieniowo przezFiles.lines(...), jak w metodziepoliczLinieZawierajace, i zawsze wtry-with-resources: strumień trzyma otwarty uchwyt do pliku, więc bez zamknięcia nie usuniesz go na Windowsie ani nie nadpiszesz, dopóki program działa.Files.lines(...)dekoduje leniwie, już w trakcie przechodzenia strumienia. Gdy plik nie jest poprawnym UTF-8, poleciUncheckedIOException— a tego zwykłycatch (IOException ...)nie złapie, bo to wyjątek niekontrolowany. Łap go osobno albo wczytuj takie pliki jako bajty.Files.exists(plik)mówi tylko, jak było w chwili sprawdzenia — między sprawdzeniem a zapisem plik może zniknąć albo pojawić się z powrotem. Zamiast dwóch kroków po prostu wykonaj operację i złapIOException.
Podobne skrypty
Listowanie i przeszukiwanie katalogów przez walkFileTree
Rekurencyjne przeglądanie drzewa katalogów przez Files.walkFileTree: limit głębokości, filtr rozszerzeń, strumieniowe szukanie treści w UTF-8 oraz jawne pomijanie dowiązań i windowsowych junctions.
średni Zobacz kod → Pliki i katalogiEksport i import CSV ze średnikiem
Samodzielny zapis i odczyt CSV w UTF-8 ze średnikiem: cytowanie, pola wielowierszowe, BOM i CRLF pod Excela, ścisły parser oraz jawny tryb chroniący arkusz przed wykonaniem formuł z niezaufanych danych.
zaawansowany Zobacz kod → Pliki i katalogiMiniatury obrazków bez zewnętrznych bibliotek
Skalowanie obrazków na czystym JDK: ImageIO wczytuje plik, Graphics2D z podpowiedziami jakości robi miniaturę z zachowaniem proporcji, a przezroczyste PNG spłaszczasz na biel przed zapisem do JPEG.
średni Zobacz kod →