Вывод иерархии папки

444
08 марта 2017, 18:07

Есть задача:

Запросить путь на папку с консоли, получить список всех папок заданной папки с учетом иерархии.

Например, поиск в папке "book" даст 5 элементов:

-book
--directory1
---file1
---file2
--directory2
---directory3
----directory4
-----directory5
------file3

Частичная реализация выглядит так:

public static void main(String[] args) {
    String scan = new Scanner(System.in).nextLine();
    System.out.println(scan);
    File dir = new File(String.valueOf(scan));
    if ( dir.isDirectory() ) {
        File[] files = dir.listFiles();
        for ( File tmpFile : files ) {
            System.out.println("-" + tmpFile.getName());
            if ( tmpFile.isDirectory() ) {
                File[] tmpFile1 = tmpFile.listFiles();
                for ( File file3 : tmpFile1 ) {
                    System.out.println("--" + file3.getName());
                }
            }
        }
    }
}

Результат:

d://book
-directory1
--file1.txt
--file2.txt
-directory2
--directory3

Результат выдает данные только до третьей директории, и ума не приложу как исправить код и довести задачу до конца.

Answer 1

Не поверите, полчаса голову ломал, так и не смог придумать решение без рекурсии. Вот код, который у меня получился

public class Main
{
static String counter = "-";
public static void main(String[] args)
{
    System.out.println("Путь к папке");
    Scanner s = new Scanner(System.in);
    String path = s.nextLine();
    File dir = new File(path);
    if(!dir.exists()){
        System.out.println("Папки с введеным именем не существует");
    }
    else if(!dir.isDirectory()){
        System.out.println("Не является папкой");
    }
    else {
        printAllFilesFromDirectory(dir);
    }
}
static void printAllFilesFromDirectory(File dir){
    for(File file : dir.listFiles()) {
        print(file);
        if(file.isDirectory()) {
            counter += "-";
            printAllFilesFromDirectory(file);
        }
    }
    counter -= "-";
}
static void print(File file){
    System.out.println(counter + " " + file.getName());
}
}

После проверок "на дурака" введеный путь передается в метод printAllFilesFromDirectory. В нем каждый файл передается методу print(), в котором выводятся тире и его имя. Количество тире опрелеляется счетчиком counter (его значение по умолчанию равно единице). После метода print если файл является директорией мы инкрементируем счетчик, так как уровень иерархии увеличился. После этого мы выполняем метод с помощью рекурсии и передаем ему директорию.

В итоге этот метод будет выводить все файлы и директории с учетом иерархии. Обратите внимание на декремент counter. Он происходит когда все файлы будут выведены! (Директории - нет, в этом случае происходит рекурсия)

Да, знаю, если путь будет слишком большой, то рекурсия станет причиной переполнения стека. Повторюсь: я не смог придумать другое решение :)

UPDATE

Теперь counter это строка (метод print выглядел по-уродски.

Answer 2

В стандартной библиотеке есть замечательный класс Files, в нем есть статический метод walkFileTree. Он нужен именно для того, что вы хотите. Т.е. для обхода дерева каталогов.

Код будет следующий:

Path parent = Paths.get("<корневая директория>");
Files.walkFileTree(parent, new SimpleFileVisitor<Path>() {
     @Override
     public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
         int count = dir.getNameCount() - parent.getNameCount() + 1;
         count += dir.getFileName().toString().length();
         //выравнивание по правому краю
         String text = String.format("%" + count + "s", dir.getFileName());
         text = text.replaceAll("[\\s]", "-");
         System.out.println(text);
         return FileVisitResult.CONTINUE;
     }
});
Answer 3

Вместо рекурсии можно использовать стек:

private static class Element
{
    public final String indent;
    public final File file;
    public Element(String indent, File file)
    {
        this.indent = indent;
        this.file = file;
    }
    public String toString()
    {
        return indent + file.getName();
    }
}
public static void main(String[] args)
{
    Scanner scanner = new Scanner(System.in);
    String path = scanner.nextLine();
    File dir = new File(path);
    if (!dir.exists() || !dir.isDirectory())
    {
        System.out.println("Incorrect directory name");
    }
    Deque<Element> stack = new ArrayDeque<>();
    stack.add(new Element("-", dir));
    while (!stack.isEmpty())
    {
        Element element = stack.pollLast();
        System.out.println(element);
        if (element.file.isDirectory())
        {
            File[] files = element.file.listFiles();
            for (int i = files.length - 1; i >=0; i--)
            {
                stack.add(new Element(element.indent + "-", files[i]));
            }
        }
    }
}

Идея остаётся та же: берём очередной файл/директорию, выводим на экран, после чего, если это директория, добавляем в обработку содержимое этой папки. И так до тех пор, пока есть что обрабатывать.

READ ALSO
Как установить layout в JavaFx?

Как установить layout в JavaFx?

Закончил изучать swing и решил попробовать javaFx, буквально с самого начала у меня появилась проблемаКак можно установить layout в JavaFX? (на данный...

397
Запрос меняется на OPTIONS

Запрос меняется на OPTIONS

Есть сервер на джаве, пишу к нему сайтПри отправке запроса POST выдает

432
Не проходит проверка на последний JSONObject

Не проходит проверка на последний JSONObject

У меня есть сервис который с определенным интервалом подключается к серверу и сверяет последний id в БДЕсли на сервере id больше, чем у меня...

278