как File.listFiles в алфавитном порядке?

95

У меня есть код, как показано ниже:

class ListPageXMLFiles implements FileFilter {

        @Override
        public boolean accept(File pathname) {
                DebugLog.i("ListPageXMLFiles", "pathname is " + pathname);

                String regex = ".*page_\\d{2}\\.xml";
                if(pathname.getAbsolutePath().matches(regex)) {
                        return true;
                }
                return false;
        }
}

public void loadPageTrees(String xml_dir_path) {
        ListPageXMLFiles filter_xml_files = new ListPageXMLFiles();
        File XMLDirectory = new File(xml_dir_path);
        for(File _xml_file : XMLDirectory.listFiles(filter_xml_files)) {
                loadPageTree(_xml_file);
        }
}

Он FileFilterработает нормально, но, listFiles()похоже, перечисляет файлы в обратном алфавитном порядке. Есть ли какой-нибудь быстрый способ listFile()указать файлы в алфавитном порядке?

Громовой кролик
источник
1
Вместо использования регулярного выражения используйте .endsWith(".xml")вместо него.
Фред

Ответы:

222

listFilesМетод, с фильтром или без него не гарантирует порядок.

Однако он возвращает массив, по которому можно выполнять сортировку Arrays.sort().

File[] files = XMLDirectory.listFiles(filter_xml_files);
Arrays.sort(files);
for(File _xml_file : files) {
    ...
}

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

Если вы предпочитаете использовать потоки:

Более современный подход заключается в следующем. Чтобы распечатать имена всех файлов в данном каталоге в алфавитном порядке, выполните:

Files.list(Paths.get(dirName)).sorted().forEach(System.out::println)

Замените на System.out::printlnвсе, что вы хотите сделать с именами файлов. Если вам нужны только имена файлов, которые заканчиваются "xml"просто do:

Files.list(Paths.get(dirName))
    .filter(s -> s.toString().endsWith(".xml"))
    .sorted()
    .forEach(System.out::println)

Опять же, замените печать любой желаемой операцией обработки.

Рэй Тоул
источник
Это прекрасная строка кода, но похоже, что Arrays.sort () возвращает void вместо Iterable. Я немного покопаюсь.
Thunder Rabbit
3
@Thunder Rabbit, мои извинения !! Извините, вы правы. Я должен был это проверить. Я отредактировал свой ответ.
Ray Toal
Вроде бы нормально работает в Windows, но в Ubuntu папки с заглавными буквами появляются первыми, чем остальные.
jmhostalet
5
Вот как я ожидал, что это сработает. Заглавные буквы идут перед строчными буквами в Юникоде. В Unix имена файлов чувствительны к регистру, поэтому сначала идут заглавные буквы. Если вы используете в Windows имена файлов без учета регистра, заглавные и строчные имена будут смешаны. Это полностью соответствует ожиданиям. Если вам нужен способ Windows в Unix, поставьте компаратор для sort.
Ray Toal
2

Я думаю, что предыдущий ответ - лучший способ сделать это, вот еще один простой способ. просто чтобы распечатать отсортированные результаты.

 String path="/tmp";
 String[] dirListing = null;
 File dir = new File(path);
 dirListing = dir.list();
 Arrays.sort(dirListing);
 System.out.println(Arrays.deepToString(dirListing));
grepit
источник
Не могли бы вы прокомментировать, почему вы думаете, что это неправильный ответ. Так что я могу его соответствующим образом пересмотреть.
grepit
1
-1 Я действительно не понимаю преимущества преобразования массива файлов в массив строк с последующей сортировкой, а не просто сортировкой массива файлов, как это делает принятый ответ.
zelanix
@zelanix благодарит за отзыв. У меня нет ответов на все вопросы, и я иногда ошибаюсь, отвечая на вопросы. Я обновил ответ, просмотрите его и посмотрите, подходит ли это решение. Буду признателен, если вы пересмотрите свой голос. Заранее спасибо.
grepit
1
Хорошо, теперь вы объясните, почему это проще, если вы просто хотите распечатать результаты, поэтому я сниму свой голос против.
zelanix
3
@ CPU100 я считаю, что использование list () вместо listFiles () дает преимущество, заключающееся в наличии только имен файлов без путей к родительским каталогам, что приводит к более коротким строкам и меньшему времени процессора для сортировки / сравнения.
Дилджит
1

В Java 8:

Arrays.sort(files, (a, b) -> a.getName().compareTo(b.getName()));

Обратный порядок:

Arrays.sort(files, (a, b) -> -a.getName().compareTo(b.getName()));
Сергей Родионов
источник
2
Вы также можете использовать этот код:Arrays.sort(fList, Comparator.comparing(File::getName));
plaidshirt
Будьте осторожны с этим. Этот код не является детерминированным и не должен использоваться как есть.
Тони Шварц,
0

Это мой код:

        try {
            String folderPath = "../" + filePath.trim() + "/";
            logger.info("Path: " + folderPath);
            File folder = new File(folderPath);
            File[] listOfFiles = folder.listFiles();
            int length = listOfFiles.length;
            logger.info("So luong files: " + length);
            ArrayList<CdrFileBO> lstFile = new ArrayList< CdrFileBO>();

            if (listOfFiles != null && length > 0) {
                int count = 0;
                for (int i = 0; i < length; i++) {
                    if (listOfFiles[i].isFile()) {
                        lstFile.add(new CdrFileBO(listOfFiles[i]));
                    }
                }
                Collections.sort(lstFile);
                for (CdrFileBO bo : lstFile) {
                    //String newName = START_NAME + "_" + getSeq(SEQ_START) + "_" + DateSTR + ".s";
                    String newName = START_NAME + DateSTR + getSeq(SEQ_START) + ".DAT";
                    SEQ_START = SEQ_START + 1;
                    bo.getFile().renameTo(new File(folderPath + newName));
                    logger.info("newName: " + newName);
                    logger.info("Next file: " + getSeq(SEQ_START));
                }

            }
        } catch (Exception ex) {
            logger.error(ex);
            ex.printStackTrace();
        }

Тру Нгуен
источник