Сортировка файлов по имени в Java отличается от Windows Explorer

У меня есть простая Java-программа, которая читает каталог файлов и выводит список файлов. Я сортирую файлы по имени:

String [] files = dirlist.list();
files = sort(files);

Моя проблема в том, что она сортируется по имени по-другому, чем Windows Explorer.

Например, если у меня есть эти файлы: abc1.doc, abc12.doc, abc2.doc.

Java будет выглядеть следующим образом:

abc1.doc
abc12.doc
abc2.doc

Когда я открываю папку в Проводнике Windows, мои файлы сортируются следующим образом:

abc1.doc
abc2.doc
abc12.doc

Как я могу сделать Java сортировать мои файлы, как в проводнике Windows? Это трюк Windows?

Ответ 1

Проводник Windows использует свой собственный алгоритм. Чтобы отсортировать файлы, такие как Explorer, вы должны создать собственный Компаратор, чтобы сделать трюк:

    public class WindowsExplorerStringComparator implements Comparator<String>
    {
      private String str1, str2;
      private int pos1, pos2, len1, len2;

      public int compare(String s1, String s2)
      {
        str1 = s1;
        str2 = s2;
        len1 = str1.length();
        len2 = str2.length();
        pos1 = pos2 = 0;

        int result = 0;
        while (result == 0 && pos1 < len1 && pos2 < len2)
        {
          char ch1 = str1.charAt(pos1);
          char ch2 = str2.charAt(pos2);

          if (Character.isDigit(ch1))
          {
            result = Character.isDigit(ch2) ? compareNumbers() : -1;
          }
          else if (Character.isLetter(ch1))
          {
            result = Character.isLetter(ch2) ? compareOther(true) : 1;
          }
          else
          {
            result = Character.isDigit(ch2) ? 1
                   : Character.isLetter(ch2) ? -1
                   : compareOther(false);
          }

          pos1++;
          pos2++;
        }

        return result == 0 ? len1 - len2 : result;
      }

      private int compareNumbers()
      {
        int end1 = pos1 + 1;
        while (end1 < len1 && Character.isDigit(str1.charAt(end1)))
        {
          end1++;
        }
        int fullLen1 = end1 - pos1;
        while (pos1 < end1 && str1.charAt(pos1) == '0')
        {
          pos1++;
        }

        int end2 = pos2 + 1;
        while (end2 < len2 && Character.isDigit(str2.charAt(end2)))
        {
          end2++;
        }
        int fullLen2 = end2 - pos2;
        while (pos2 < end2 && str2.charAt(pos2) == '0')
        {
          pos2++;
        }

        int delta = (end1 - pos1) - (end2 - pos2);
        if (delta != 0)
        {
          return delta;
        }

        while (pos1 < end1 && pos2 < end2)
        {
          delta = str1.charAt(pos1++) - str2.charAt(pos2++);
          if (delta != 0)
          {
            return delta;
          }
        }

        pos1--;
        pos2--; 

        return fullLen2 - fullLen1;
      }

      private int compareOther(boolean isLetters)
      {
        char ch1 = str1.charAt(pos1);
        char ch2 = str2.charAt(pos2);

        if (ch1 == ch2)
        {
          return 0;
        }

        if (isLetters)
        {
          ch1 = Character.toUpperCase(ch1);
          ch2 = Character.toUpperCase(ch2);
          if (ch1 != ch2)
          {
            ch1 = Character.toLowerCase(ch1);
            ch2 = Character.toLowerCase(ch2);
          }
        }

        return ch1 - ch2;
      }
    }

Теперь используйте его следующим образом:

  Arrays.sort(files, new WindowsExplorerStringComparator());

Ответ 2

Это выглядит так.

Однако вы можете использовать Arrays.sort() и предоставить пользовательский Comparator, чтобы он сортировался, как и проводник Windows.

Ответ 3

Сортировка по строке, затем по длине имени.

Ответ 4

Это еще одна попытка реализовать его в Java:

Java - Сортировка строк, таких как проводник Windows

Короче говоря, он разделяет две строки для сравнения в Letter-Digit Parts и сравнивает эти части определенным образом для достижения такого рода сортировки.

С этим его IMHO немного читаем.