Как прочитать все файлы из папки в Java? (рекурсивно и нет)
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
public class ReadFiles {
public static void main(String[] args) {
File folder = new File("data");
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles) {
if (file.isFile()) {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
}
}
}
Но код выдаёт ошибку "NullPointerException" на строке `for (File file : listOfFiles)`. Что я делаю не так? Как правильно получить список файлов? И ещё: внутри папки могут быть подпапки, как мне обработать их рекурсивно? Буду благодарен за подробное объяснение с рабочими примерами.
<<Основная проблема: NullPointerException
Ошибка возникает, потому что метод listFiles() возвращает null, если переданная директория не существует или возникла ошибка ввода-вывода. В вашем случае папка "data" не найдена (например, не та рабочая директория). Всегда проверяйте результат на null:
File folder = new File("data");
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
// обработка
}
} else {
System.out.println("Папка не найдена: " + folder.getAbsolutePath());
}
Правильный способ: Java 7+ (NIO.2)
Начиная с Java 7, рекомендуется использовать пакет java.nio.file. Он более надёжный и производительный. Вот два основных подхода:
1. Чтение всех файлов (не рекурсивно)
import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;
public class ReadFilesNIO {
public static void main(String[] args) throws IOException {
Path dir = Paths.get("data");
// Используем try-with-resources для автоматического закрытия потока
try (Stream<Path> paths = Files.list(dir)) {
paths
.filter(Files::isRegularFile) // только файлы, не папки
.forEach(path -> {
try {
String content = Files.readString(path);
System.out.println("Файл: " + path.getFileName());
System.out.println(content);
} catch (IOException e) {
System.err.println("Ошибка чтения: " + path);
}
});
}
}
}
2. Рекурсивный обход (включая подпапки)
import java.nio.file.*;
import java.io.IOException;
import java.util.stream.Stream;
public class ReadFilesRecursive {
public static void main(String[] args) throws IOException {
Path startDir = Paths.get("data");
// Files.walk() обходит всё дерево рекурсивно
try (Stream<Path> paths = Files.walk(startDir)) {
paths
.filter(Files::isRegularFile)
.forEach(path -> {
try {
// Читаем файл как строку (Java 11+)
String content = Files.readString(path);
System.out.println("Файл: " + path);
System.out.println(content);
System.out.println("---");
} catch (IOException e) {
System.err.println("Ошибка: " + path);
}
});
}
}
}
Важные моменты:
- Files.list() — только файлы и папки первого уровня (не рекурсивно).
- Files.walk() — рекурсивный обход всех поддиректорий.
- Files.readString() доступен с Java 11. Для более старых версий используйте
Files.readAllLines()илиnew String(Files.readAllBytes(path)). - try-with-resources автоматически закрывает поток, чтобы избежать утечек.
- Всегда обрабатывайте
IOException— файлы могут быть недоступны.
Пример с фильтрацией по расширению
try (Stream<Path> paths = Files.walk(Paths.get("data"))) {
paths
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".txt"))
.forEach(path -> {
// обработка только .txt файлов
});
}
Если вам нужно читать файлы построчно (например, для больших файлов), используйте Files.lines() — он возвращает Stream<String>.
Альтернативный подход: классический File + рекурсия
Если вы по какой-то причине не можете использовать NIO (например, очень старая версия Java), вот решение на основе java.io.File с рекурсивным обходом:
import java.io.*;
public class ReadFilesLegacy {
public static void main(String[] args) {
File root = new File("data");
processDirectory(root);
}
private static void processDirectory(File dir) {
File[] files = dir.listFiles();
if (files == null) return; // защита от ошибок
for (File file : files) {
if (file.isDirectory()) {
processDirectory(file); // рекурсия для подпапок
} else if (file.isFile()) {
readFile(file);
}
}
}
private static void readFile(File file) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("Ошибка: " + file.getAbsolutePath());
}
}
}
Дополнительные советы:
- Используйте
File.listFiles(FileFilter)для фильтрации на уровне ОС (например, только .txt файлы). - Для больших объёмов данных переходите на NIO — он работает быстрее и надёжнее.
- Не забывайте про кодировку:
new FileReader(file, StandardCharsets.UTF_8).
Этот вариант полностью решает вашу задачу, но в современной Java предпочтительнее использовать java.nio.file.