WedX - журнал о программировании и компьютерных науках

Java: рекурсивный поиск файлов (с относительными путями) для передачи в качестве переменной

...думал, что это будет просто... :/

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

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

Lil background: эта программа будет перемещена в разные папки в зависимости от года и штата, чтобы преобразовывать текстовые файлы в табличный формат для контроля качества данных. У меня есть код анализа текстового файла, который отлично работает, но мне нужно автоматизировать получение файлов журнала для каждого округа в штате.

Я реализовал код для поиска текущего рабочего каталога:

File workingDir = new File(new File(".").getAbsolutePath());
Path workDir = Paths.get(workingDir.getCanonicalPath());

Я получаю оба, потому что я не добился достаточного прогресса, чтобы понять, что мне действительно нужно...

Я (спасибо ТАК!!) смог рекурсивно найти все файлы из рабочего каталога:

        Files.find(Paths.get(workDir.toString()),
        Integer.MAX_VALUE,
        (filePath, fileAttr) -> fileAttr.isRegularFile())
        .forEach(System.out::println);

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

    //List of input files for bufferedreader:
    java.util.List<String> inputFiles = new ArrayList<String>();

... а затем изменив блок "Files.find(paths...") на:

.forEach(inputFiles.add());

... не работает. Я понятия не имею, что передать в качестве аргументов, и '...inputFiles.add()' не будет компилироваться (JDK 10) без аргументов.

Я попробовал PathMatcher, но не смог понять, как сопоставить тип функции, которой я ее передал, чтобы код скомпилировался.

Вот мой шаблон в стандартном регулярном выражении:

Pattern logFile = Pattern.compile("Correct_[\\d]{4}-[\\d]{2}-[\\d]{2}_[\\d]{2}-[\\d]{2}.txt");

Шаблон переводится как: «Правильно_гггг-ММ-дд_ЧЧ-ММ.txt».

Мне не удалось скомпилировать следующее с ошибкой «.java:87: не удается найти символ» в «Коллекторе» в «.collect(Collectors.toList());»:

inputFiles = Files.walk(Paths.get(workDir.toString()))
                            .filter(Files::isRegularFile)
                            .map(Path::toFile)
                            .collect(Collectors.toList());

Я импортировал java.io., java.io.File., java.nio.* и java.nio.file.* в первые строки кода.

Очевидно, я не понимаю file.io/file.nio, и я не смог сгенерировать рабочий код после прочтения документации/учебников Oracle и многочисленных SO и других форумов/сайтов.

Может кто-то указать мне верное направление?

Большое спасибо!


  • Вы импортировали java.util.strams.Collectors? без него вы не можете вызвать Collectors.toList() 16.07.2018
  • @Assafs, в конце концов, но я столкнулся с другой ошибкой компиляции, а затем пошел на обед. --Должна встречаться, но скоро сообщу подробности! Спасибо!! 17.07.2018
  • Похоже, это может потребовать от вас выполнения шагов отладки. После того, как вы пройдете все очевидные вопросы, если у вас все еще есть проблема, пожалуйста, обновите вопрос с новым статусом, и я постараюсь помочь. 17.07.2018
  • @Assafs, с импортированным util.stream я получаю .java:88: ошибка: несовместимые типы: переменная вывода T имеет несовместимые границы .collect(Collectors.toList()); Я еще не настолько далеко, чтобы отлаживать: у меня нет даже минимально работающего кода. :( 17.07.2018
  • Проблема в том, что мы не можем вести здесь долгий разговор. Я напишу ответ ниже с тем, что я знаю до сих пор, и я отредактирую его, как вы продолжите. Это нормально? 17.07.2018
  • @Assfs, звучит здорово! Спасибо! 17.07.2018
  • Сделанный. Если вы считаете, что это поможет вам, я буду признателен, если вы проголосуете за ответ, нажав на серую стрелку вверх рядом с ним, и если вы считаете, что это достаточно хорошо отвечает на вопрос, рассмотрите возможность его принятия, нажав на серая галочка рядом с ним, делая его зеленым. Удачи! 17.07.2018

Ответы:


1

Исходная проблема, о которой вы сообщили, была java:87: error: cannot find symbol" on 'Collector' in ".collect(Collectors.toList());. Глядя на ошибку, проблема хорошо сформулирована - вы не импортировали java.util.stream.Collectors в свой код.

Но как только вы импортировали его, у вас возникла другая проблема — java:88: error: incompatible types: inference variable T has incompatible bounds .collect(Collectors.toList());. Обычно это означает, что пар не дает нужного типа. Вам нужно значение для inputFiles, которое имеет тип List<String>. Вы получаете коллекцию List<File>, потому что ранее вы использовали Path.toFile() на карте. Я предлагаю вам удалить карту (оставить ее как список путей) или изменить inputFiles на List<File>.

Кстати, вы можете увидеть, как перейти к обработке этой ошибки в этом посте, например: -has-incompiled-bounds-equality/41719150">java: несовместимые типы: переменная вывода T имеет несовместимые границы.

В общем, лучше всего отлаживать свой код по одной ошибке компиляции за раз и просто искать сообщения в SO, относящиеся к ошибке, которую вы получаете. Этот вид процесса может быть итеративным и занять некоторое время.

16.07.2018

2

Не найдя пошагового руководства, но многочисленные примеры без объяснений, ПОЧЕМУ и КАК запускать рекурсивный поиск файлов с использованием регулярных выражений и передачи результата в переменную, я пишу один:

ВНИМАНИЕ: Я НОВИЧОК. Я многого не знаю или не совсем понимаю. В этом посте я излагаю самые современные то, что я знаю. Пожалуйста, поймите, что «то, что я знаю» на момент написания может быть неверным и неполным. Как говорится, поправки только приветствуются! Спасибо!

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

Следующие две строки кода дадут вам путь к рабочему каталогу вашего Java-приложения. ПРИМЕЧАНИЕ: это должно быть расположением, из которого выполняется приложение.

Не забудьте импортировать соответствующие библиотеки. Я изучаю Java, поэтому не заинтересован в изучении чьей-либо любимой библиотеки дополнений, поэтому я придерживаюсь только библиотек Oracle Java. ПОЗЖЕ, когда у меня будет приличный опыт разработки на Java, я начну изучать крутые, удивительные возможности надстроек.

import java.io.*;
import java.io.File.*;
import java.nio.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import static java.nio.file.FileVisitResult.*;
import static java.nio.file.FileVisitOption.*;
import java.util.*;
import java.util.stream.*;
import java.util.regex.*;

ПРИМЕЧАНИЕ. Если вы получаете сообщение «не удается найти символ» или ошибки времени компиляции в методе, который вы захватили из SO или другого онлайн-ресурса, возможно, у вас нет импортированной библиотеки. ...спросите меня, откуда я знаю. ;)

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

    File workingDir = new File(new File(".").getAbsolutePath());
    Path workDir = Paths.get(workingDir.getCanonicalPath());

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

Во второй строке указывается абсолютный путь к файлу "." (исключая имя файла) в переменную. Путь начинается с корневого каталога (т. е. с буквы диска в среде Windows). Дополнительную информацию об абсолютном каноническом пути можно найти примерно на 2/3 здесь: Описание абсолютного/канонического пути

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

   java.util.List<String> files = new ArrayList<>();

Примечание. Я должен включить «java.util». в объявлении «Список», потому что я импортировал другие библиотеки, которые без него делают объявление неоднозначным. Ни один из этих кодов не актуален, поэтому не включен.

Теперь о рекурсивном поиске. Опять же, нет не-хакерского способа сделать это. Я предполагал, что это будет делаться достаточно часто, чтобы для этого был разработан чистый метод - я имею в виду, что я знаю как минимум 3 разных способа написать цикл for! - но я думаю, это отражает то, что люди в Oracle, разрабатывающие Java, используют больше, чем то, что простые «пользователи» (мы) делают с продуктом.

Я решил использовать PathMatcher, потому что мне также нужно указать папки, чтобы не искать файлы. 'Files.find()' и многочисленные классы, которые талантливые люди пытались запрограммировать, не имели такого простого метода для этого.

final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("regex:.*Correct_\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}\\.txt");
Files.walkFileTree(Paths.get(workDir.toString()), new SimpleFileVisitor<Path>() 
{
    @Override
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
    {
        if (dir.getFileName().toString().equals("Reprocess"))
        {
             return SKIP_SUBTREE;
        }
        return CONTINUE;
    }//end public preVisitDirectory
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException 
    {
        if (matcher.matches(file))
        {
            files.add(file.toString());
        }//end if(matcher)
    return FileVisitResult.CONTINUE;
    }//end visitFile
    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException 
    {
    return FileVisitResult.CONTINUE;
    }//end visitFileFailed
});//end Files.walkFileTree1

Пара замечаний по моему коду: 1. Как начинающий программист, я считаю полезным отслеживать закрывающие фигурные скобки, чтобы обозначить, кому принадлежит каждая из них; 2. Мое регулярное выражение очень специфично, потому что я ищу программный вывод - каждый раз он будет одним и тем же.

Объявление PathMatcher: Final указывает Java, что это не изменится. «FileSystems.getDefault()» идентифицирует ОС, поэтому косые черты указывают правильный путь (среди прочего). 'getPathMatcher(' выполняет функцию, подобную 'Pattern.compile()'.

«regex:» определяет поиск как «regex», а не как поиск «glob». Я выделил эту строку, потому что было трудно найти пример синтаксиса для регулярного выражения в этом контексте.

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

Files.walkFileTree: выполнение метода 'walkFileTree' класса Files с 'Paths.get(' в качестве аргумента. 'Paths.get(' имеет рабочий каталог, который мы установили ранее, в качестве аргумента.

Ранее я упоминал, что использование чего-то «совместимого» между файлами, путями и файловыми системами не имеет значения. Что ж, при моем нынешнем уровне навыков единственный способ передать объект «Список» для информации о пути — сначала сделать его строковым объектом. Итак, у нас есть "workDir.toString()". К вашему сведению, жесткое кодирование пути к моему рабочему каталогу также сработало.

ПРИМЕЧАНИЕ. «..» указывает относительный путь к местоположению, из которого было выполнено приложение Java. Вот почему я сказал ранее, что моя программа «может» должна знать свой рабочий каталог — оказывается, моя не знает, а ваша может. Вместо этого я использую свою переменную, содержащую абсолютный путь к моему рабочему каталогу (никакого заметного влияния на выполнение моего кода). Вы можете передать «..» (включая двойные кавычки) вместо «workDir.toString()», если вам просто нужен относительный путь.

новый SimpleFileVisitor: экземпляр простого посетителя файлов.

Первый аргумент указывает инструкции preVisitDirectory; здесь я указываю своей программе не выполнять поиск в папке «Повторно обработать». Есть много других инструкций, которые можно вставить сюда, если это необходимо.

Второй аргумент указывает, что моя программа должна делать, когда находит совпадение — в этом случае совпадение добавляется в список «файлов» ArrayList.

Третий аргумент предписывает программе не беспокоиться, если совпадение не найдено.

Конец.

Ну, не совсем, но этот код выполняет рекурсивный поиск файлов с использованием регулярных выражений и выводит совпадения с переменной (в данном случае ArrayList).

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

Удачи! Не стесняйтесь обращаться ко мне (если это так), если у вас есть какие-либо вопросы, комментарии или проблемы.

Джейк

ОБНОВЛЕНИЕ: мне удалось выяснить, как передавать имена файлов в FileInputStream. Изменения, ниже:

java.util.List<String> files = new ArrayList<>();

стал:

java.util.List<File> files = new ArrayList<>();

аргумент visitFule в функции Files.walkFileTree стал таким:

public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException 
            {
                if (matcher.matches(file))
                {
                    files.add(file.toFile());
//'files.add(file.toString());' changed
                }//end if(matcher)

Следующий код был добавлен для преобразования ArrayList файлов в fileArray, Array, затем преобразования каждого элемента в Array в строку во время выполнения и передачи этой строки в FileInputStream (обернутый в BufferedReader).

int fLength = files.size();
File[] fileArray = files.toArray(new File[fLength]);
for(int f=0; f<files.size(); f++)
{
//log file Reader init:
    String corrFile = fileArray[f].toString();
    BufferedReader corrReader = new BufferedReader(new InputStreamReader(new FileInputStream(corrFile),"UTF-16LE"));
        //NOTE: PFO differential correction log files are encoded in UTF-16 LE

...аааааааааааааааааааааааааааааааааааааааааа! Этот аспект моего проекта завершен и работает правильно.

17.07.2018
Новые материалы

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

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]