Как найти самый большой файл в каталоге при помощи Java

User Rating: 0 / 5

Доброго времени суток, друзья. В сегодняшней небольшой статье мы посмотрим на один из вариантов поиска самого большого файла в каталоге при помощи 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, если вы на нашем сайте впервые. Спасибо за внимание и удачи!

 

 

Яндекс.Метрика