在 Java 中按名称排序文件与 Windows 资源管理器不同

Posted

技术标签:

【中文标题】在 Java 中按名称排序文件与 Windows 资源管理器不同【英文标题】:Sort files by name in Java differs from Windows Explorer 【发布时间】:2011-03-05 05:59:52 【问题描述】:

我有一个简单的 Java 程序,它读取文件目录并输出文件列表。 我按名称对文件进行排序:

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

我的问题是它按名称排序的方式与 Windows 资源管理器不同。

例如,如果我有这些文件:abc1.doc、abc12.doc、abc2.doc。

Java 会这样排序:

abc1.doc
abc12.doc
abc2.doc

当我在 Windows 资源管理器中打开文件夹时,我的文件排序如下:

abc1.doc
abc2.doc
abc12.doc

如何让 Java 像在 Windows 资源管理器中那样对文件进行排序? 这是 Windows 的把戏吗?

【问题讨论】:

见***.com/questions/442429/windows-explorer-sort-method 【参考方案1】:

Windows 资源管理器使用自己的算法。为了像 Explorer 一样对文件进行排序,您应该创建一个自定义 Comparator 来解决问题:

    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());

【讨论】:

我想补充一点:名为“files”的参数必须是String[]类型【参考方案2】:

看起来是这样的。

但是,您可以使用 Arrays.sort() 并提供自定义的 Comparator,这样它就可以像 Windows 资源管理器那样进行排序。

【讨论】:

【参考方案3】:

按字符串排序,然后按名称长度。

【讨论】:

【参考方案4】:

这是在 Java 中实现它的另一个尝试:

Java - Sort Strings like Windows Explorer

简而言之,它将两个字符串拆分为字母 - 数字部分进行比较,并以特定方式比较这部分以实现这种排序。

有了这个,恕我直言,更具可读性。

【讨论】:

以上是关于在 Java 中按名称排序文件与 Windows 资源管理器不同的主要内容,如果未能解决你的问题,请参考以下文章

如何在 GORM 中按排序顺序保存数据

如何编写自定义排序器以在 UI 中按名称对 springdoc swagger 标签进行排序?

在 PHP 中按整数键对对象进行排序

在 django(postgres 后端)中按数字字符串排序查询结果

在 C# 中按名称获取 Windows 窗体控件

双向链表中按字母顺序排序的链接