Search code examples
javawindows-explorer

Sort files by name in Java differs from Windows Explorer


I have a simple Java program which reads a file directory and outputs a file list. I sort the files by name:

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

My problem is that it sorts by name in a different way than Windows Explorer does.

For instance if I have these files: abc1.doc, abc12.doc, abc2.doc.

Java will sort like this:

abc1.doc
abc12.doc
abc2.doc

When I open the folder in Windows Explorer, my files are sorted like this:

abc1.doc
abc2.doc
abc12.doc

How can I make Java sort my files like in Windows Explorer? Is this a Windows trick?


Solution

  • Windows Explorer uses its own algorithm. In order to sort your files like Explorer does, you should create a custom Comparator to do the trick:

        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;
          }
        }
    

    Now, use it like this:

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