Przejdź do treści

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.

JAVA PlikiTekstowe.java 128 linii Pobierz .java
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

  1. Skopiuj kod i zapisz go w pliku o nazwie PlikiTekstowe.java — takiej samej jak nazwa klasy publicznej — a następnie uruchom go poleceniem java PlikiTekstowe.java. Demonstracja pracuje w katalogu tymczasowym systemu i na końcu sama po sobie sprząta, więc niczego nie zaśmieci.
  2. We własnym projekcie skopiuj potrzebne metody do swojej klasy narzędziowej. Ścieżkę zbudujesz przez Path.of("dane", "raport.txt") albo katalog.resolve("raport.txt") — nie sklejaj ścieżek ręcznie ukośnikami.
  3. Pamiętaj, że zapisz(...) nadpisuje plik bez pytania, a dopisz(...) 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.
  4. Prawie każda metoda deklaruje throws IOException — jedynym wyjątkiem jest istnieje(...) — więc wywołania musisz otoczyć blokiem try/catch albo przekazać wyjątek wyżej. Zobacz, jak zrobiono to w main.

Warto wiedzieć

  • Metody klasy Files bez argumentu Charset zakładają UTF-8, ale FileReader, FileWriter czy new String(bajty) aż do Javy 17 brały domyślne kodowanie systemu. Podawaj StandardCharsets.UTF_8 wprost, a nie będziesz musiał pamiętać, która metoda należy do której grupy.
  • readString i readAllLines wczytują cały plik do pamięci — przy logu na kilkaset megabajtów dostaniesz OutOfMemoryError. Wtedy czytaj strumieniowo przez Files.lines(...), jak w metodzie policzLinieZawierajace, i zawsze w try-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, poleci UncheckedIOException — a tego zwykły catch (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łap IOException.
#pliki #nio #path #utf-8 #polskie znaki #stream api

Podobne skrypty