1. Tworzenie katalogów
Katalog (czyli folder) — to nie tylko kontener na pliki, lecz podstawa organizacji danych na dysku. W aplikacjach stale tworzymy katalogi dla danych wejściowych/wyjściowych, logów, plików tymczasowych itd. Nowoczesne API java.nio.file robi to wygodnie i wieloplatformowo.
Zobaczmy, jak tworzyć, usuwać i przeglądać zawartość folderów za pomocą klas Files, Path i Paths.
Files.createDirectory(path)
Tworzy jeden katalog pod wskazaną ścieżką. Jeśli katalog nadrzędny nie istnieje — zostanie rzucony wyjątek.
import java.nio.file.*;
public class DirectoryDemo {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("testDir");
if (!Files.exists(dir)) {
Files.createDirectory(dir);
System.out.println("Utworzono katalog: " + dir.toAbsolutePath());
} else {
System.out.println("Katalog już istnieje: " + dir.toAbsolutePath());
}
}
}
Jeśli spróbujesz utworzyć katalog, który już istnieje, otrzymasz FileAlreadyExistsException.
Files.createDirectories(path)
Tworzy cały łańcuch katalogów. Jeśli któregoś z katalogów pośrednich brakuje — zostanie utworzony automatycznie. Jeśli część łańcucha już istnieje — błąd nie wystąpi.
Path nestedDir = Paths.get("parent/child/grandchild");
Files.createDirectories(nestedDir);
System.out.println("Utworzono łańcuch katalogów: " + nestedDir.toAbsolutePath());
To tak, jakbyś poprosił Javę, aby zbudowała nie tylko dom, ale także klatkę schodową i ulicę, jeśli jeszcze ich nie było.
Typowy przykład: tworzymy strukturę dla projektu
Załóżmy, że trzeba zapisywać raporty do folderu output/reports/2024. Nie sprawdzaj każdego katalogu ręcznie — użyj createDirectories.
Path reportsPath = Paths.get("output/reports/2024");
Files.createDirectories(reportsPath);
Java sama ustali, co już istnieje, a co należy utworzyć.
2. Usuwanie plików i katalogów
Files.delete(path)
Usuwa plik albo pusty katalog. Jeśli katalog nie jest pusty — zostanie rzucony DirectoryNotEmptyException.
Path dir = Paths.get("testDir");
try {
Files.delete(dir);
System.out.println("Katalog usunięto: " + dir.toAbsolutePath());
} catch (DirectoryNotEmptyException e) {
System.out.println("Nie można usunąć: katalog nie jest pusty!");
}
Files.deleteIfExists(path)
Działa jak delete, ale nie zgłasza błędu, gdy obiekt nie istnieje. Zwraca true, jeśli coś zostało usunięte, i false — jeśli obiektu nie było.
Path file = Paths.get("output/reports/2024/report.txt");
if (Files.deleteIfExists(file)) {
System.out.println("Plik usunięty.");
} else {
System.out.println("Pliku nie znaleziono, nic nie usunięto.");
}
Jak usunąć niepusty katalog?
Nie da się ot tak usunąć niepustego folderu. Najpierw trzeba usunąć całą jego zawartość (pliki i podkatalogi), a następnie sam folder. Robi się to rekurencyjnie, np. przez Files.walkFileTree:
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class DeleteDirectoryRecursively {
public static void main(String[] args) throws IOException {
Path dir = Paths.get("parent");
if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
System.out.println("Katalog i cała jego zawartość zostały usunięte.");
}
}
}
Jeśli dopiero zaczynasz, nie przerażaj się tym kodem — później omówimy walkFileTree dokładniej.
3. Przeglądanie zawartości katalogu
Files.list(path)
Zwraca Stream<Path> — strumień ścieżek. Możesz przetwarzać zawartość folderu za pomocą Stream API. Każdy element — plik lub podkatalog (bez rekurencji!).
Path dir = Paths.get("output/reports");
if (Files.exists(dir) && Files.isDirectory(dir)) {
try (var stream = Files.list(dir)) {
stream.forEach(path -> System.out.println(path.getFileName()));
}
}
Ważna uwaga: strumień trzeba koniecznie zamknąć, dlatego używamy try‑with‑resources.
Przykład: wypisywanie nazw plików i podkatalogów
Path reports2024 = Paths.get("output/reports/2024");
try (var stream = Files.list(reports2024)) {
stream.forEach(path -> {
String type = Files.isDirectory(path) ? "katalog" : "plik";
System.out.println(path.getFileName() + " — " + type);
});
}
Uzyskanie listy plików jako kolekcji
List<Path> files = Files.list(reports2024)
.filter(Files::isRegularFile)
.toList();
System.out.println("Pliki w folderze:");
files.forEach(System.out::println);
Ważne: Files.list(path) zwraca tylko zawartość bieżącego katalogu (najwyższy poziom). Do rekurencyjnego przejścia użyj Files.walk(path).
4. Praktyka: mini‑menedżer plików
Narzędzie tworzy katalog mydata/logs, plik log1.txt, wypisuje zawartość folderu i następnie wszystko usuwa.
import java.nio.file.*;
import java.io.IOException;
public class MiniFileManager {
public static void main(String[] args) throws IOException {
Path logsDir = Paths.get("mydata/logs");
Files.createDirectories(logsDir);
Path logFile = logsDir.resolve("log1.txt");
Files.writeString(logFile, "Cześć, log!");
System.out.println("Zawartość folderu " + logsDir + ":");
try (var stream = Files.list(logsDir)) {
stream.forEach(path -> System.out.println(" - " + path.getFileName()));
}
Files.deleteIfExists(logFile);
Files.deleteIfExists(logsDir);
System.out.println("Plik i folder zostały usunięte.");
}
}
Komentarze do kodu:
- Files.createDirectories gwarantuje utworzenie całego łańcucha.
- resolve — wygodny sposób dodania do ścieżki nazwy pliku.
- Zamykamy strumień z Files.list przez try‑with‑resources — szczególnie istotne w Windows.
5. Specyfika i niuanse
Sprawdzenie istnienia
Przed utworzeniem/usunięciem warto sprawdzić, czy ścieżka istnieje:
if (!Files.exists(path)) {
Files.createDirectory(path);
}
Uprawnienia dostępu
Jeśli program nie ma uprawnień do tworzenia/usuwania — otrzymasz AccessDeniedException. Na przykład utworzenie folderu w katalogu głównym dysku przez zwykłego użytkownika prawie zawsze zakończy się błędem.
Pusta i niepusta direktoria
Usunąć można tylko pusty katalog (Files.delete). Do usuwania wraz z całą zawartością użyj przejścia rekurencyjnego (walkFileTree).
Wieloplatformowość
API java.nio.file poprawnie działa na wszystkich popularnych systemach operacyjnych i uwzględnia separatory ścieżek. Do budowania ścieżek używaj Paths.get i Path.resolve, a nie sklejaj łańcuchów.
Linki symboliczne
W podstawowych zadaniach nie trzeba o nich myśleć, ale jeśli spotkasz „nietypowe” wpisy, które nie są ani zwykłym plikiem, ani katalogiem — możliwe, że to symlinki. Wrócimy do nich w bardziej zaawansowanych wykładach.
6. Typowe błędy przy pracy z katalogami
Błąd nr 1: próba usunięcia niepustego katalogu prostym wywołaniem Files.delete(path). Java rzuci DirectoryNotEmptyException. Najpierw usuń zawartość, potem sam folder.
Błąd nr 2: zapomniano zamknąć strumień z Files.list(). Jeśli nie użyjesz try‑with‑resources, strumień pozostanie otwarty i w Windows może wystąpić błąd przy usuwaniu folderu.
Błąd nr 3: tworzenie katalogu bez sprawdzenia istnienia katalogu nadrzędnego. Wywołanie Files.createDirectory dla ścieżki typu parent/child, gdy parent nie istnieje, spowoduje NoSuchFileException. Użyj Files.createDirectories.
Błąd nr 4: używanie ścieżek bezwzględnych bez potrzeby. Preferuj ścieżki względne w obrębie projektu — dzięki temu kod będzie bardziej przenośny.
Błąd nr 5: brak obsługi IOException. Każda operacja na systemie plików może zakończyć się błędem. Opakuj w try-catch albo przekaż wyjątek wyżej.
Błąd nr 6: próba utworzenia/usunięcia w folderze, do którego brak uprawnień. W takim przypadku otrzymasz AccessDeniedException. Sprawdź kontekst uruchomienia i uprawnienia dostępu.
GO TO FULL VERSION