Невозможно отсортировать список файлов, где имя файла будет содержать метку времени, используя Коллекции (Java) - PullRequest
3 голосов
/ 04 июля 2019

У меня есть arrayList, который содержит список файлов, имена которых действительно являются временными метками.

List<File> fileList = new ArrayList<>();
fileList.add(new File("20190612221053"));
fileList.add(new File("20190512221303"));
fileList.add(new File("20190612221353"));
fileList.add(new File("20190512222303"));
fileList.add(new File("20190612221303"));

Формат отметки времени: «ггггммдд ЧЧмммм».

Моя цель - отсортировать этот список в порядке возрастания временных отметок, указанных в именах файлов.

Соответственно, я использую метод Collections.sort, как показано ниже:

Collections.sort(fileList, new Comparator<File>() {
    @Override
    public int compare(File file1, File file2) {
        Date timeStamp1=null,timeStamp2=null;
        try {
            timeStamp1 = new SimpleDateFormat("yyyymmddHHssmm").parse(file1.getName());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        try {
            timeStamp2 = new SimpleDateFormat("yyyymmddHHssmm").parse(file2.getName());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        if(timeStamp1!=null && timeStamp2!=null && timeStamp1.getTime()!=timeStamp2.getTime() ) {
            return (timeStamp1.getTime() > timeStamp2.getTime()) ? 1 : -1;
        }
        else {
            return 0;
        }
    }
});

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

[20190512221303, 20190512222303, 20190612221053, 20190612221303, 20190612221353]

Но вместо этого я получаю заказ:

[20190512221303, 20190612221303, 20190512222303, 20190612221053, 20190612221353]

Ясно, что что-то идет не так. Может кто-нибудь указать, где я делаю это неправильно.

Ответы [ 2 ]

1 голос
/ 04 июля 2019

В коде есть две основные ошибки

  1. Логика сравнения

Используйте

Long.compare(timeStamp1.getTime(), timeStamp2.getTime());

для правильного сравнения двух longчисло

Шаблон даты

переключатель mm -> MM на месяц.

1 голос
/ 04 июля 2019

Вы можете попробовать это с помощью Java 8:

List<File> ordered = fileList.sort((o1, o2) ->
    Long.valueOf(Long.valueOf(o1.getName()) - Long.valueOf(o2.getName())).intValue());

Обычно вы преобразуете имена файлов в числа (структура yyyymmddHHssmm гарантирует, что у более новых файлов будут большие значения Long), затем вычисляете разницу, используя компаратор и вызывая сортировку List # с указанным компаратором

ordered будет содержать упорядоченный список файлов

Если вам нужен обратный порядок, поменяйте местами операторы следующим образом:

Long.valueOf(Long.valueOf(o2.getName()) - Long.valueOf(o1.getName())).intValue()


Редактировать

было отмечено, что структура имени файла выглядит следующим образом: yyyymmddHHmmss_someName.extension

Следовательно, значение даты должно быть сначала извлечено из имени файла перед выполнением сравнения.

В этом случае код должен быть:

    fileList.sort(
        (o1, o2) ->
            Long.valueOf(
                    Long.valueOf(o1.getName().split(Pattern.quote("_"))[0])
                        - Long.valueOf(o2.getName().split(Pattern.quote("_"))[0]))
                .intValue());

В этой версии имя файла разделено на символ _, извлекается ссылка на дату. Затем дата преобразуется в число и используется для сравнения файлов.


Edit2

Если имя файла динамическое и оно содержит ссылку ггггммдд ЧЧммсс в имени, то вы можете сделать что-то вроде этого:

    Pattern pattern = Pattern.compile("\\d{14}");

    fileList.sort(
        (o1, o2) -> {
          Matcher m1 = pattern.matcher(o1.getName());
          m1.find();
          String date1 = m1.group(0);
          Long num1 = Long.valueOf(date1);
          Matcher m2 = pattern.matcher(o2.getName());
          m2.find();
          String date2 = m2.group(0);
          Long num2 = Long.valueOf(date2);
          return Long.valueOf(num1 - num2).intValue();
        });

Ссылка на дату извлекается из любой части имени файла.

Вы можете добавить дополнительные проверки к вызовам .find(), чтобы проверить, соответствует ли имя файла ожидаемому шаблону.


Edit3

Решение может быть улучшено путем добавления проверки шаблона имени файла с помощью Необязательно:

    long minVal = 19700101000000L ;
    Pattern pattern = Pattern.compile("\\d{14}");

    fileList.sort(
        (o1, o2) -> {
          Long num1 =
              Optional.of(pattern.matcher(o1.getName()))
                  .filter(Matcher::find)
                  .map(m -> Long.valueOf(m.group(0)))
                  .orElse(minVal);

          Long num2 =
              Optional.of(pattern.matcher(o2.getName()))
                  .filter(Matcher::find)
                  .map(m -> Long.valueOf(m.group(0)))
                  .orElse(minVal);

          return Long.valueOf(num1 - num2).intValue();
        });

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

Надеюсь, это поможет

...