Рекурсия: проверка файлов в каталогах и их чтение

Прежде чем вы выскажете что-то вроде «Этот парень просит помочь с домашним заданием», я продолжу и развею все ваши сомнения и скажу да, это связано с домашним заданием. Тем не менее, я надеюсь, что это не умаляет знаний, которые этот вопрос дает мне и / или любому, кто прочитает это в будущем.

Предыстория: в настоящее время мы работаем над рекурсией, и наше задание требует, чтобы мы написали программу, которая использует аргументы команды для проверки каталога и содержимого его файла на наличие строки (это также аргумент команды). Мы должны использовать рекурсию для этого.


- Я хочу прояснить, что Я ПОНИМАЮ, ЧТО ЗАДАЕТ ЗАДАНИЕ. Я просто спрашиваю, как это будет работать рекурсивно, потому что я просто не понимаю.

Мы решили задачу, где нам нужно было найти размер каталога, и это имело смысл, но я не понимаю, как проверить, является ли что-то каталогом или файлом, и на основе этого мы читаем его содержимое или углубляемся в каталог до тех пор, пока находим файл.


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

Папка, которую я проверяю, выглядит примерно так: Каталог ---> файлы --внутри основного каталога --->> Два каталога --> файлы в обоих этих каталогах

открытый класс SearchingForStrings {

public static void main(String[] args) {
    String path = "."; // default location of this project
    File sf = new File(path);
    String mysteriesDirectory = args[0];
    String keyString = args[1];

    countLinesWithString(sf, mysteriesDirectory, keyString);
}

public static int countLinesWithString(File startPath, String mysteriesDirectory, String keyString) {
    if(!startPath.exists()) {
        throw new IllegalArgumentException("File " + startPath + " does not exist!");
    } else if(startPath.isFile()) {
        return Integer.parseInt(startPath.getAbsolutePath()); // Just to show where the file is I located the parsing is just to stop an error from flagging on this part; Going to ask professor if it's okay with him


        // this is where we would begin reading the contents of the files
    } else if(startPath.isDirectory()) {
        // This is where our recursion would take place: essentially
        // we will be going 'deeper' into the directory until we find a file

        //File[] subFiles = startPath.listFiles();
        countLinesWithString(startPath, mysteriesDirectory, keyString);
    } else {
        throw new IllegalStateException("Unknown file type: " + startPath);
    }

}

}

Вкратце: может ли кто-нибудь объяснить, как будет работать рекурсия, если вы хотите углубиться в директора (y / ies)?


person N.P    schedule 02.11.2014    source источник


Ответы (2)


Я попробую. Это то, что легче объяснить, чем понять.

Рекурсивный метод, с которого вы неплохо начали, можно задокументировать следующим образом:

«Для данного каталога: для каждого файла в каталоге подсчитайте все строки, содержащие данную строку; для каждого каталога в каталоге рекурсивно».

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

Итак, подумайте о методе подсчета следующим образом:

int countLines(dir, string)  // the string could be an instance variable, also, and not passed in
{
  var countedLines = 0;
  for each item in dir:
    if item is file, countedLines += matchedLinesInFile(item, string);
    else if item is dir, countedLines += countLines(item, string);
    else throw up;  // or throw an exception -- your choice
}

затем вызовите countLines из внешнего метода с использованием исходного каталога и строки.

Одна из вещей, которая смущает людей в рекурсии, заключается в том, что после того, как вы ее написали, кажется невозможным, что она может делать все то, что она делает. Но продумайте вышеизложенное для разных сценариев. Если в переданном каталоге есть файлы и нет каталогов, он будет накапливать countedLines для каждого файла в каталоге и возвращать результат. Это то, что ты хочешь.

Если каталог содержит другие каталоги, то для каждого из них вы вызовете процедуру и начнете с этого содержащегося каталога. Вызов будет накапливать countedLines для каждого файла в этом каталоге и вызывать себя для каждого каталога рекурсивно вниз по дереву, пока не достигнет каталога, в котором нет каталогов. И он по-прежнему считает строки в них, просто ему больше некуда рекурсировать.

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

Это лучше объясняет?

person arcy    schedule 02.11.2014
comment
В этом есть смысл - попробую утром, потому что я не спал с 2 часов ночи 31 октября, и уже почти пора спать. Я отвечу тогда, если вы все еще готовы дать больше советов. Еще раз спасибо за полезный вклад - вернусь завтра утром. - person N.P; 02.11.2014
comment
Немного подумав об этом, я не могу понять, что вы здесь написали, особенно бит «элемент». Что такое «элемент», я понимаю, что это файл, но что это такое? Это переменная, содержащая место файла, или я должен создать новый файл в пути? и почему - person N.P; 02.11.2014
comment
Я попытался определить это с помощью начала цикла: для каждого элемента в директории. Элемент - это одна вещь в каталоге, может быть (для этой цели) либо файлом (данных), либо другим каталогом. Другими словами, это переменная, содержащая ссылку либо на файл данных, либо на каталог; цикл проходит через каждый такой элемент в каталоге, переданном методу в качестве параметра. (не ожидал, что ты вернешься к этому так скоро...) - person arcy; 02.11.2014
comment
Итак, вы выполняете рекурсию для обоих утверждений else-if? Я не понимаю ту часть, где вы написали matchedLinesInFile. Это новый метод, который вы написали или? Кроме того, я пошел дальше и прошел по каталогам, но я все еще не знаю, как читать файлы. Я что-то написал, но на самом деле это не считает прочитанные строки. - person N.P; 03.11.2014
comment
matchedLinesInFile(file) — метод, который я не показывал; он берет файл данных (который не является каталогом) и читает его, считая строки, соответствующие строке. Ваш вопрос задан о рекурсии; в этой части их нет. Вы можете посмотреть на любой пример, где Java читает текстовый файл построчно, и добавить свой код, чтобы определить, содержит ли одна строка целевую строку; эта подпрограмма имеет свой собственный локальный счетчик, установленный на 0, и увеличивает его при каждом совпадении. После завершения файла он возвращает общее количество совпадений. В приведенном выше рекурсия происходит только в 1-м else. - person arcy; 03.11.2014
comment
Извините за задержку с ответом. Догадаться. Решил всю программу, и теперь я понимаю, как она работает, поэтому я чувствую себя намного увереннее в своем понимании рекурсии. - person N.P; 03.11.2014

Просто помогите вам начать работу с рекурсией, проверьте это: он будет рекурсивно идти из базового каталога, печатая все папки и файлы. Измените это в соответствии с вашими требованиями. Попробуйте и дайте нам знать.

import java.io.File;

public class Test {


    public static void getResource(final String resourcePath) {

        File file = new File(resourcePath);
        if (file.isFile()) {
            System.out.println("File Name : " + file.getName());
            return;
        } else {
            File[] listFiles = file.listFiles();
            if (listFiles != null) {
                for (File resourceInDirectory : listFiles) {

                    if (!resourceInDirectory.isFile()) {
                        System.out.println("Folder "
                                + resourceInDirectory.getAbsolutePath());
                        getResource(resourceInDirectory.getAbsolutePath());
                    } else {
                        getResource(resourceInDirectory.getAbsolutePath());
                    }

                }
            }

        }
    }

    public static void main(String[] args) {

        final String folderPath = "C:/Test";
        getResource(folderPath);
    }

}
person jithin iyyani    schedule 02.11.2014
comment
Я честно не хочу пробовать это; Мне нужно объяснение, а не ответ. Если я попробую это, у меня просто возникнут ложные моменты озарения, потому что ответ будет совать мне в лицо. Спасибо, но нет. - person N.P; 02.11.2014
comment
Вы не научитесь писать рекурсивные функции, пока не попробуете. Запустите код один раз. Отладьте код. Добавьте несколько точек отладки. Смотрите трассировку звонков. Нарисуйте поток на бумаге. После этого, я уверен, у вас наступит момент озарения. :) Поверьте мне. - person jithin iyyani; 02.11.2014
comment
Как мне отладить что-то, если я не понимаю основы его функциональности? Я не могу сказать, где в вашей программе происходит рекурсия - если она вообще есть, поэтому я не могу ничего добавить к ней. - person N.P; 02.11.2014
comment
Если вы внимательно посмотрите, например, если вы видите, что getResource вызывает getResource. - person jithin iyyani; 02.11.2014
comment
stackoverflow.com/questions/9199984/basic-java-recursion-method попробуйте прочитать это. - person jithin iyyani; 02.11.2014
comment
Здесь уже поздно, так что извините, я этого не видел. Когда вы вызываете getResource(resourceIntDirectory.getAbsolutePath()), теперь вы используете каталог внутри основного каталога? Я предполагаю, что это то, для чего. - person N.P; 02.11.2014
comment
Давайте продолжим обсуждение в чате. - person N.P; 02.11.2014