“目录优先”命令的比较器

我很难过……假设我有这个目录树:

{someRoot}/ {someRoot}/bar/ {someRoot}/bar/file1.txt {someRoot}/foo/ {someRoot}/foo/baz/ {someRoot}/foo/baz/file3.txt {someRoot}/foo/abracadabra.txt {someRoot}/foo/file2.txt {someRoot}/aardvark.txt {someRoot}/food.txt {someRoot}/zebra.txt 

你会注意到订购。 叫这个订单1 。 在每个阶段,目录首先出现在文件之前。 ( 注意: bar/file1.txtfoo之前出现,因此在全局范围内,目录并非都在所有文件之前。)

如果我枚举这个目录树,然后递归枚举子目录,我将得到以下List ,订购order2

 {someRoot}/ {someRoot}/aardvark.txt {someRoot}/bar/ {someRoot}/foo/ {someRoot}/food.txt {someRoot}/zebra.txt {someRoot}/bar/file1.txt {someRoot}/foo/abracadabra.txt {someRoot}/foo/baz/ {someRoot}/foo/file2.txt {someRoot}/foo/baz/file3.txt 

如果我创建简单的Comparator

 Comparator fc = new Comparator(){ @Override public int compare(File o1, File o2) { return o1.compareTo(o2); } }; 

我排序,我从词典排序得到这个排序( order3 ):

 {someRoot} {someRoot}/aardvark.txt {someRoot}/bar {someRoot}/bar/file1.txt {someRoot}/foo {someRoot}/food.txt {someRoot}/foo/abracadabra.txt {someRoot}/foo/baz {someRoot}/foo/baz/file3.txt {someRoot}/foo/file2.txt {someRoot}/zebra.txt 

但是我不想要这个排序(有问题:注意food.txt介于目录foo和它的子项之间),我想要order1 。 我怎么能写一个比较器来帮我这个?

这适用于我的测试。

 new Comparator() { @Override public int compare(File first, File second) { if (first.isDirectory() && second.isDirectory()) return first.compareTo(second); if (first.isDirectory()) return this.compareToFile(first, second); if (second.isDirectory()) return -(this.compareToFile(second, first)); return this.compareFiles(first, second); } private int compareFiles(File first, File second) { File firstParentFile = first.getParentFile(); File secondParentFile = second.getParentFile(); if (isSubDir(firstParentFile, secondParentFile)) return -1; if (isSubDir(secondParentFile, firstParentFile)) return 1; return first.compareTo(second); } private int compareToFile(File directory, File file) { File fileParent = file.getParentFile(); if (directory.equals(fileParent)) return -1; if (isSubDir(directory, fileParent)) return -1; return directory.compareTo(file); } private boolean isSubDir(File directory, File subDir) { for (File parentDir = directory.getParentFile(); parentDir != null; parentDir = parentDir.getParentFile()) { if (subDir.equals(parentDir)) { return true; } } return false; } 

这个recursivly获取您喜欢的排序文件树:

 public static void main(String[] args) { List files = getFileTree(new File(".")); for (File f : files) System.out.println(f); } private static List getFileTree(File file) { List files = new LinkedList(); files.add(file); if (file.isDirectory()) { File[] current = file.listFiles(); Arrays.sort(current, new Comparator() { @Override public int compare(File o1, File o2) { if (o1.isDirectory()) return o2.isDirectory() ? o1.compareTo(o2) : -1; else if (o2.isDirectory()) return 1; return o1.compareTo(o2); } }); for (File f : current) files.addAll(getFileTree(f)); } return files; } 
 Comparator fc = new Comparator(){ @Override public int compare(File o1, File o2) { boolean isFirstDirectory = o1.isDirectory(); boolean isSecondDirectory = o2.isDirectory(); if(!isFirstDirectory && !isSecondDirectory) { return o1.compareTo(o2); } else if (isFirstDirectory && !isSecondDirectory){ return (int) 1; } else if(isSecondDirectory && !isFirstDirectory) { return -1; } else { return o1.compareTo(o2); } } }; 

编辑您必须比较第一级的基本目录和第二级的文件名

 import java.io.File; import java.io.IOException; import java.util.Comparator; public class FileComparator implements Comparator { @Override public int compare(File o1, File o2) { int pathCompare = this.getPath(o1).compareTo(this.getPath(o2)); if (pathCompare != 0) { return subPathCompare; } else { if (o1.isDirectory() && !o2.isDirectory()) { return -1; } else if (!o1.isDirectory() && o2.isDirectory()) { return 1; } else { return o1.compareTo(o2); } } } //maybe there is a better way to speparete path and file name, but it works private String getPath(File file) { if (file.isFile()) { return file.getParent().toLowerCase(); } else { return file.getPath().toLowerCase(); } } } 

如果路径和文件的分离是必要的,因为如果只做一个:

  if (o1.isDirectory() && !o2.isDirectory()) { return -1; } else if (!o1.isDirectory() && o2.isDirectory()) { return 1; } else { return o1.compareTo(o2); } 

结果不是案例1,而是另一个案例,其中所有directorys都是第一个项目,文件是最后一个:

  \dir1\ \dir2\ \dir3\ \dir4\ \dir1\file1\ \dir1\file2\ \dir2\file1\ \dir2\file2\ 

所以我的解决方案是首先检查两个比较文件是否属于同一目录。

  • 如果它们不属于同一目录,那么它们将通过那个目录进行比较。
  • 如果属于同一目录,则子directorys在“正常文件之前”“排序”。

我确实找到了一种方法来实现我想要的伪对立(文件之后的目录,没有检查文件和目录名在根级别的边缘情况)。

……不,将它转换成我想要的东西并不是微不足道的,因为我正在使用目录的词典排序,它将不同级别的目录排序和同一级别的目录排序结合起来。

 static class FileDirectoryPriorityComparator implements Comparator { @Override public int compare(File f1, File f2) { if (f1.isDirectory()) { if (f2.isDirectory()) { return f1.compareTo(f2); } else { return compareDirFile(f1, f2); } } else { if (f2.isDirectory()) { return -compareDirFile(f2, f1); } // f1 and f2 are both files else { return compareFiles(f1, f2); } } } private int compareDirFile(File dir, File file) { /* * If dir compares differently to file's parent, use that ordering. * Otherwise, dir comes before file. */ File fparent = file.getParentFile(); if (fparent == null) return -1; int i = dir.compareTo(fparent); if (i != 0) return i; return -1; } private int compareFiles(File f1, File f2) { /* * If f1's parent compares differently to f2's parent, use that ordering. * Otherwise use default ordering. */ File fp1 = f1.getParentFile(); File fp2 = f2.getParentFile(); if (fp1 == null) { if (fp2 != null) { return 1; } } else { if (fp2 == null) { return -1; } else { int i = fp1.compareTo(fp2); if (i != 0) return i; } } return f1.compareTo(f2); } } 

当然为时已晚。 无论如何,这里有一个Comparator实现,按照SO中的要求进行排序。

 public class DirectoryBeforeFileComparator implements Comparator { @Override public int compare(File o1, File o2) { if (o1.isDirectory() && !o2.isDirectory()) { // directory before non-directory. return -1; } if (!o1.isDirectory() && o2.isDirectory()) { // non-directory after directory return 1; } // compare two pathnames lexicographically return o1.compareTo(o2); } }