Доброго времени суток, друзья. В сегодняшней небольшой статье мы посмотрим на один из вариантов поиска самого большого файла в каталоге при помощи Java.
Попробуем решить эту задачу, используя лишь два стандартных класса Java - java.io.File и java.util.Arrays
Как мы знаем, директории в файловой системе образуют вложенную структуру, т.е. в одних каталогах могут быть и файлы, и другие каталоги. Во вложенных каталогах также могут быть или файлы, или каталоги и так далее. Напрашивается мысль о том, что наш алгоритм поиска самого большого файла в каталоге должен быть рекурсивным. То есть он примет какой-то основной каталог, где мы ищем файл, и будет его просматривать вглубь, пытаясь найти самый большой файл среди всех остальных. Для того, чтобы нам сделать рекурсивный обход в этом алгоритме эффективным и куда-то "складывать" информацию о самом большом на текущий момент файле (т.е. на момент просмотра алгоритмом каталога, когда мы находимся на определённом уровне вложенности), нам нужна какая-то структура с именем файла и информацией о его размере. Давайте зададим такой класс MaxFileInfo (мы сразу сделаем его статическим и затем встроим в класс основной программы-примера):
/**
* [RU] Класс для хранения информации о самом большом файле
* [EN] Class for storing the information about the largest file
*/
public static class MaxFileInfo {
/**
* [RU] Хранит размер файла, в байтах
* [EN] Stores the file size, in bytes
*/
private long length;
/**
* [RU] Имя файла
* [EN] The file name
*/
private String fileName;
public long getLength() {
return length;
}
/**
* [RU] Возвращает размер файла, в килобайтах
* [EN] Returns the file size, in Kilobytes
* @return [RU] размер файла (Кб); [EN] file size (Kb)
*/
public double getLengthKb() {
return length / 1024d;
}
/**
* [RU] Возвращает размер файла, в мегабайтах
* [EN] Returns the file size, in Megabytes
* @return [RU] размер файла (Мб); [EN] file size (Mb)
*/
public double getLengthMb() {
return length / 1048576d;
}
public void setLength(long length) {
this.length = length;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
Как видите, класс содержит лишь два поля для хранения размера файла (в байтах) и названия файла. Также есть методы getLengthKb() и getLengthMb(), вычисляющие размер файла в килобайтах и мегабайтах, соответственно.
После того, как мы определили класс для хранения информации о самом большом файле, давайте теперь напишем метод для рекурсивного обхода всех каталогов, начиная с текущего. На вход наш метод будет принимать текущий корневой каталог parentDirectory, с которого начинаем поиск, а также ссылку maxFileInfo на экземпляр класса MaxFileInfo, который мы уже рассмотрели выше:
public static void getMaxFileInfo(String parentDirectory, MaxFileInfo maxFileInfo) {
if (maxFileInfo == null) {
throw new IllegalArgumentException("`maxFileInfo` parameter cannot be null!");
}
File f = new File(parentDirectory);
File[] files = f.listFiles();
if (files == null || files.length == 0) {
return;
}
Arrays.stream(files).forEach(file -> {
if (file.isDirectory()) {
getMaxFileInfo(file.getPath(), maxFileInfo);
} else {
long length = file.length();
if (length > maxFileInfo.getLength()) {
maxFileInfo.setLength(length);
maxFileInfo.setFileName(file.getName());
}
}
});
}
Давайте разберём алгоритм этого метода. Итак, на входе мы проверяем, что если ссылка на текущий максимальный файл равна null, то это явно ошибка (скорее всего метод был вызван с некорректным значением параметра), поэтому мы сразу выбрасываем исключение IllegalArgumentException:
if (maxFileInfo == null) {
throw new IllegalArgumentException("`maxFileInfo` parameter cannot be null!");
}
Затем мы создаём экземпляр стандартного класса File и вызываем следующей строкой метод listFiles() для получения всех директорий и файлов внутри этого каталога. Сразу после этого мы проверяем - не пуст ли этот список, и, если пуст, то возвращаемся из нашего метода, ничего не делая далее:
File f = new File(parentDirectory);
File[] files = f.listFiles();
if (files == null || files.length == 0) {
return;
}
Если же файлы/директории присутствуют, то мы их пробегаем с помощью метода forEach, и для каждого текущего элемента file мы исполняем блок логики в фигурных скобках. Этот блок содержит лишь один оператор if, работающий следующим образом:
- если текущий элемент - это директория, то вызываем рекурсивно "самих себя", т.е. этот же метод getMaxFileInfo.
- если же текущий элемент - это файл, то мы получаем его размер в байтах с помощью вызова file.length(), а затем лишь сравниваем с текущей длиной нашего максимального файла, хранящегося по ссылке в maxFileInfo. Если длина текущего элемента (т.е. файла) больше, то мы перезаписываем информацию о длине файла и его имени в ссылке maxFileInfo, вызывая методы setLength и setFileName
Вот как это выглядит в коде:
Arrays.stream(files).forEach(file -> {
if (file.isDirectory()) {
getMaxFileInfo(file.getPath(), maxFileInfo);
} else {
long length = file.length();
if (length > maxFileInfo.getLength()) {
maxFileInfo.setLength(length);
maxFileInfo.setFileName(file.getName());
}
}
});
На этом весь алгоритм завершён. С помощью этого кода мы теперь можем рекурсивно обойти любой каталог любого уровня вложенности.
Осталось дело за малым - нам теперь нужно поместить наш статический класс MaxFileInfo, а также метод getMaxFileInfo в какой-то исполняемый класс и написать лишь простую логику вызова нашего рекурсивного метода. Пусть наш файл с примером будет называться MaxFileInfoExample. Вот как будут выглядеть его части и его метод main:
package ru.allineed.samples.files.max_file_info;
import ru.allineed.samples.common.OutputUtils;
import ru.allineed.samples.config.Localization;
import java.io.File;
import java.util.Arrays;
public class MaxFileInfoExample {
public static class MaxFileInfo {
// ... здесь идёт содержимое класса MaxFileInfo, что рассмотрели выше
}
public static void getMaxFileInfo(String parentDirectory, MaxFileInfo maxFileInfo)
{
// ... здесь идёт тело метода getMaxFileInfo, что рассмотрели выше
}
public static void main(String[] args) {
OutputUtils.printSampleTitle(
"Как найти самый большой файл в каталоге при помощи Java",
"How to find the largest file in the directory using Java",
"https://allineed.ru/development/java-development/67-java-how-to-find-largest-file");
// [RU] При желании здесь можно поменять путь к каталогу на что-то вида:
// String path = "C:\\DIR1\\SUB_DIR2\\SUB_DIR3";
// [EN] If you want you can change the path to the target directory with something like:
// String path = "C:\\DIR1\\SUB_DIR2\\SUB_DIR3";
String path = System.getProperty("user.dir");
MaxFileInfo maxFileInfo = new MaxFileInfo();
getMaxFileInfo(path, maxFileInfo);
String resultInfo = Localization.getLocalized(
String.format("Найден самый большой файл в каталоге '%s': имя = %s, размер = %.2f Мб%n",
path,
maxFileInfo.getFileName(),
maxFileInfo.getLengthMb()
),
String.format("The largest file is found in the directory '%s': name = %s, size = %.2f Mb%n",
path,
maxFileInfo.getFileName(),
maxFileInfo.getLengthMb()
)
);
System.out.println(resultInfo);
}
}
Обратите внимание, что в качестве исходного каталога для вызова метода getMaxFileInfo мы задаём переменную path, которая будет равна текущему рабочему каталогу пользователя. Подробнее о стандартных системных свойствах в Java можно прочитать на официальном сайте. Также мы создаём экземпляр класса MaxFileInfo с именем maxFileInfo, которая будет хранить первично нулевой размер максимального файла и пустое имя файла. Оба параметра мы передаём в наш метод getMaxFileInfo:
String path = System.getProperty("user.dir");
MaxFileInfo maxFileInfo = new MaxFileInfo();
getMaxFileInfo(path, maxFileInfo);
Наконец, после отработки рекурсивного метода, самый большой файл в каталоге будет найден. Остаётся лишь сформировать информационную строку resultInfo с именем и размером файла, после чего вывести её на экран консоли.
Ну вот и всё на этом, можете запустить программу и посмотреть на результат - в консоли отобразится информация о найденном файле с максимальным размером. Также можете поэкспериментировать и вместо рабочего каталога пользователя задать какой-то другой существующий путь к каталогу вашей файловой системы. Программа сможет найти самый большой файл в этом указанном каталоге.
Делитесь мыслями в комментариях под статьей. Также внизу вы найдете ссылку на этот пример в нашем Git-репозитории и инструкцию по запуску всех примеров на Java, если вы на нашем сайте впервые. Спасибо за внимание и удачи!
Примеры из этой статьи: https://github.com/AllineedRu/JavaExamples/blob/main/allineed-core/src/main/java/ru/allineed/samples/files/max_file_info/MaxFileInfoExample.java