【问题标题】:Best way to list files in Java, sorted by Date Modified?在Java中列出文件的最佳方法,按修改日期排序?
【发布时间】:2010-09-17 05:04:21
【问题描述】:

我想获取目录中的文件列表,但我想对其进行排序,以便最旧的文件排在第一位。我的解决方案是调用 File.listFiles 并根据 File.lastModified 重新排序列表,但我想知道是否有更好的方法。

编辑:按照建议,我目前的解决方案是使用匿名比较器:

File[] files = directory.listFiles();

Arrays.sort(files, new Comparator<File>(){
    public int compare(File f1, File f2)
    {
        return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
    } });

【问题讨论】:

  • 这个“新长”部分是怎么回事?你为什么不比较多头本身呢?这样可以避免您为了使用 compareTo 方法而创建大量多头...
  • 此代码无法编译。 compare 方法期望返回的是 int 而不是 Long。
  • 我是唯一一个认为这个解决方案很疯狂的人吗?您多次致电file.lastModified()。最好先获取所有日期,然后再订购,以便每个文件只调用一次 file.lastModified()
  • 可以使用 apache commons 比较器:Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
  • Java 8 有更好的解决方案(请参阅 viniciussss 答案):Arrays.sort(files, Comparator.comparingLong(File::lastModified));

标签: java file sorting


【解决方案1】:

我认为您的解决方案是唯一明智的方法。获取文件列表的唯一方法是使用 File.listFiles() 并且文档指出这不能保证返回文件的顺序。因此,您需要编写一个使用File.lastModified()Comparator,并将其与文件数组一起传递给Arrays.sort()

【讨论】:

【解决方案2】:

自 Java 8 以来的优雅解决方案:

File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified));

或者,如果您希望它按降序排列,只需将其反转:

File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());

【讨论】:

  • 这确实是最简单的解决方案。对于列表:files.sort(Comparator.comparingLong(File::lastModified));
  • @starbroken 如果文件是由 directory.listFiles() 返回的简单数组,如 File[],则您的解决方案不起作用。
  • @starbroken 要使您的解决方案发挥作用,需要使用 ArrayList&lt;File&gt; files = new ArrayList&lt;File&gt;(Arrays.asList(directory.listFiles())) ,这并不比 File[] files = directory.listFiles() 更容易。
  • 是的,我同意你的看法。如果您有一组文件,则没有理由创建列表。 (如果有人想知道,viniciussss 评论中的“附加”ArrayList&lt;File&gt;(...) 需要获得一个可以排序的可变列表。)我发现这个线程正在寻找一种对文件列表进行排序的方法。所以我只是添加了该代码,以便人们在碰巧也有列表时可以简单地复制它。
  • Comparator 类没有任何方法调用comparingLong
【解决方案3】:

如果您有很多文件,这可能会更快。这使用了 decorate-sort-undecorate 模式,因此每个文件的最后修改日期只被提取一次,而不是每次排序算法比较两个文件时。这可能会将 I/O 调用的数量从 O(n log n) 减少到 O(n)。

不过,它的代码更多,因此只有在您主要关心速度并且在实践中明显更快(我尚未检查)时才应该使用它。

class Pair implements Comparable {
    public long t;
    public File f;

    public Pair(File file) {
        f = file;
        t = file.lastModified();
    }

    public int compareTo(Object o) {
        long u = ((Pair) o).t;
        return t < u ? -1 : t == u ? 0 : 1;
    }
};

// Obtain the array of (file, timestamp) pairs.
File[] files = directory.listFiles();
Pair[] pairs = new Pair[files.length];
for (int i = 0; i < files.length; i++)
    pairs[i] = new Pair(files[i]);

// Sort them by timestamp.
Arrays.sort(pairs);

// Take the sorted pairs and extract only the file part, discarding the timestamp.
for (int i = 0; i < files.length; i++)
    files[i] = pairs[i].f;

【讨论】:

  • 最佳答案,因为如果 lastModified 在排序时发生更改,它可能是唯一防止“比较方法违规错误”的答案?
  • 当您担心由于比较方法违规而无法获得 IllegalArgumentException 时,也应该使用此选项。如果有多个文件具有相同的 lastModified 值,则使用 Map 的方法将失败,这将导致忽略这些文件。这绝对应该是一个公认的答案。
【解决方案4】:

类似的方法是什么,但没有对 Long 对象进行装箱:

File[] files = directory.listFiles();

Arrays.sort(files, new Comparator<File>() {
    public int compare(File f1, File f2) {
        return Long.compare(f1.lastModified(), f2.lastModified());
    }
});

【讨论】:

  • 这似乎只是 API 19+。
  • 使用 return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());而不是较低的api。
【解决方案5】:

您还可以查看apache commons IO,它有一个内置的last modified comparator 和许多其他用于处理文件的不错的实用程序。

【讨论】:

  • 此解决方案的 javadoc 中有一个奇怪的错误,因为 javadoc 说要使用“LastModifiedFileComparator.LASTMODIFIED_COMPARATOR.sort(list);”对列表进行排序,但 LASTMODIFIED_COMPARATOR 被声明为“Comparator”,因此它不公开任何“排序”方法。
  • 像这样使用它:link
  • File.lastModified 可能会在对最终结果进行排序时发生更改,导致比较方法违规错误,请参阅:stackoverflow.com/questions/20431031 请参阅stackoverflow.com/a/4248059/314089 以获得可能的更好解决方案。
  • 爱 apache commons,节省了很多时间,
【解决方案6】:

在 Java 8 中:

Arrays.sort(files, (a, b) -&gt; Long.compare(a.lastModified(), b.lastModified()));

【讨论】:

    【解决方案7】:

    如果您正在排序的文件可以在执行排序的同时进行修改或更新:


    Java 8+

    private static List<Path> listFilesOldestFirst(final String directoryPath) throws IOException {
        try (final Stream<Path> fileStream = Files.list(Paths.get(directoryPath))) {
            return fileStream
                .map(Path::toFile)
                .collect(Collectors.toMap(Function.identity(), File::lastModified))
                .entrySet()
                .stream()
                .sorted(Map.Entry.comparingByValue())
    //            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))  // replace the previous line with this line if you would prefer files listed newest first
                .map(Map.Entry::getKey)
                .map(File::toPath)  // remove this line if you would rather work with a List<File> instead of List<Path>
                .collect(Collectors.toList());
        }
    }
    

    Java 7

    private static List<File> listFilesOldestFirst(final String directoryPath) throws IOException {
        final List<File> files = Arrays.asList(new File(directoryPath).listFiles());
        final Map<File, Long> constantLastModifiedTimes = new HashMap<File,Long>();
        for (final File f : files) {
            constantLastModifiedTimes.put(f, f.lastModified());
        }
        Collections.sort(files, new Comparator<File>() {
            @Override
            public int compare(final File f1, final File f2) {
                return constantLastModifiedTimes.get(f1).compareTo(constantLastModifiedTimes.get(f2));
            }
        });
        return files;
    }
    


    这两种解决方案都创建了一个临时地图数据结构,以保存目录中每个文件的恒定最后修改时间。我们需要这样做的原因是,如果在执行排序时您的文件正在更新或修改,那么您的比较器将违反比较器接口通用合同的传递性要求,因为最后修改时间可能在比较期间发生变化。

    另一方面,如果您知道文件不会在您的排序过程中被更新或修改,那么您几乎可以放弃提交给这个问题的任何其他答案,我偏向于:

    Java 8+(排序期间无并发修改)

    private static List<Path> listFilesOldestFirst(final String directoryPath) throws IOException {
        try (final Stream<Path> fileStream = Files.list(Paths.get(directoryPath))) {
            return fileStream
                .map(Path::toFile)
                .sorted(Comparator.comparing(File::lastModified))
                .map(File::toPath)  // remove this line if you would rather work with a List<File> instead of List<Path>
                .collect(Collectors.toList());
        }
    }
    

    注意:我知道您可以通过在排序流操作中使用Files::getLastModifiedTime api 来避免上述示例中的文件对象之间的转换,但是,您需要在 lambda 中处理已检查的 IO 异常,这总是一种痛苦。我会说如果性能足够关键以至于翻译是不可接受的,那么我要么通过将其作为 UncheckedIOException 传播来处理 lambda 中的已检查 IOException,要么我完全放弃 Files api 并仅处理 File 对象:

    final List<File> sorted = Arrays.asList(new File(directoryPathString).listFiles());
    sorted.sort(Comparator.comparing(File::lastModified));
    

    【讨论】:

      【解决方案8】:

      进口:

      org.apache.commons.io.comparator.LastModifiedFileComparator
      

      Apache Commons

      代码:

      public static void main(String[] args) throws IOException {
              File directory = new File(".");
              // get just files, not directories
              File[] files = directory.listFiles((FileFilter) FileFileFilter.FILE);
      
              System.out.println("Default order");
              displayFiles(files);
      
              Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
              System.out.println("\nLast Modified Ascending Order (LASTMODIFIED_COMPARATOR)");
              displayFiles(files);
      
              Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
              System.out.println("\nLast Modified Descending Order (LASTMODIFIED_REVERSE)");
              displayFiles(files);
      
          }
      

      【讨论】:

      • 目前尚不清楚 LastModifiedFileComparator.LASTMODIFIED_COMPARATOR 是从哪里获取的。也许添加到apache commons io 的链接会有所帮助。
      • 完成,谢谢宽带
      【解决方案9】:
      public String[] getDirectoryList(String path) {
          String[] dirListing = null;
          File dir = new File(path);
          dirListing = dir.list();
      
          Arrays.sort(dirListing, 0, dirListing.length);
          return dirListing;
      }
      

      【讨论】:

      【解决方案10】:

      如果有人正在寻找它,这是 Kotlin 的做法:

      val filesList = directory.listFiles()
      
      filesList?.let{ list ->
          Arrays.sort(list) { 
              f1, f2 -> f2.lastModified().compareTo(f1.lastModified()) 
          }
      }
      

      【讨论】:

        【解决方案11】:
        Collections.sort(listFiles, new Comparator<File>() {
                public int compare(File f1, File f2) {
                    return Long.compare(f1.lastModified(), f2.lastModified());
                }
            });
        

        其中listFiles是ArrayList中所有文件的集合

        【讨论】:

          【解决方案12】:

          你可以试试番石榴Ordering:

          Function<File, Long> getLastModified = new Function<File, Long>() {
              public Long apply(File file) {
                  return file.lastModified();
              }
          };
          
          List<File> orderedFiles = Ordering.natural().onResultOf(getLastModified).
                                    sortedCopy(files);
          

          【讨论】:

            【解决方案13】:

            您可以使用 Apache LastModifiedFileComparator

             import org.apache.commons.io.comparator.LastModifiedFileComparator;  
            
            
            File[] files = directory.listFiles();
                    Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
                    for (File file : files) {
                        Date lastMod = new Date(file.lastModified());
                        System.out.println("File: " + file.getName() + ", Date: " + lastMod + "");
                    }
            

            【讨论】:

              【解决方案14】:
              private static List<File> sortByLastModified(String dirPath) {
                  List<File> files = listFilesRec(dirPath);
                  Collections.sort(files, new Comparator<File>() {
                      public int compare(File o1, File o2) {
                          return Long.compare(o1.lastModified(), o2.lastModified());
                      }
                  });
                  return files;
              }
              

              【讨论】:

                【解决方案15】:

                让数组名 -> 文件。


                Ascending -> Arrays.sort(files, (o1, o2) -> Long.compare(o1.lastModified(), o2.lastModified()));
                
                Descending -> Arrays.sort(files, (o1, o2) -> Long.compare(o2.lastModified(), o1.lastModified()));
                

                【讨论】:

                  【解决方案16】:

                  当我在android 搜索相同的问题时,我来到了这篇文章。 我并不是说这是按上次修改日期排序文件的最佳方式,但它是我发现的最简单的方式。

                  以下代码可能对某人有所帮助-

                  File downloadDir = new File("mypath");    
                  File[] list = downloadDir.listFiles();
                      for (int i = list.length-1; i >=0 ; i--) {
                          //use list.getName to get the name of the file
                      }
                  

                  谢谢

                  【讨论】:

                  • 但是谁来排序呢?
                  • for 循环的初始化部分,您可以看到我已将 list.length-1 提升到 i &gt;=0,它们只是以相反的顺序迭代您。
                  【解决方案17】:

                  有一种非常简单方便的方法来处理该问题,而无需任何额外的比较器。只需将修改后的日期编码到带有文件名的字符串中,对其进行排序,然后再次将其剥离。

                  使用一个固定长度为 20 的字符串,将修改后的日期(长)放入其中,并用前导零填充。然后只需将文件名附加到此字符串:

                  String modified_20_digits = ("00000000000000000000".concat(Long.toString(temp.lastModified()))).substring(Long.toString(temp.lastModified()).length()); 
                  
                  result_filenames.add(modified_20_digits+temp.getAbsoluteFile().toString());
                  

                  这里发生了什么:

                  文件名 1:C:\data\file1.html 上次修改时间:1532914451455 上次修改时间 20 位:00000001532914451455

                  文件名1:C:\data\file2.html 最后修改:1532918086822 最后修改20位:00000001532918086822

                  将电影名转换为:

                  文件名1:00000001532914451455C:\data\file1.html

                  文件名2:00000001532918086822C:\data\file2.html

                  然后您可以对这个列表进行排序。

                  您需要做的就是稍后再次删除这 20 个字符(在 Java 8 中,您可以使用 .replaceAll 函数仅用一行将其删除为整个数组)

                  【讨论】:

                    【解决方案18】:

                    @jason-orendorf 的answer 稍微现代化的版本。

                    注意:此实现保持原始数组不变,并返回一个数组。这可能是可取的,也可能是不可取的。

                    files = Arrays.stream(files)
                            .map(FileWithLastModified::ofFile)
                            .sorted(comparingLong(FileWithLastModified::lastModified))
                            .map(FileWithLastModified::file)
                            .toArray(File[]::new);
                    
                    private static class FileWithLastModified {
                        private final File file;
                        private final long lastModified;
                    
                        private FileWithLastModified(File file, long lastModified) {
                            this.file = file;
                            this.lastModified = lastModified;
                        }
                    
                        public static FileWithLastModified ofFile(File file) {
                            return new FileWithLastModified(file, file.lastModified());
                        }
                    
                        public File file() {
                            return file;
                        }
                    
                        public long lastModified() {
                            return lastModified;
                        }
                    }
                    

                    但同样,@jason-orendorf 的所有功劳归于idea

                    【讨论】:

                      【解决方案19】:

                      在java 6中,最好的方法是:

                        File[] listaArchivos = folder.listFiles();
                                  Arrays.sort(listaArchivos, new Comparator<File>() {
                                      @Override
                                      public int compare(File f1, File f2) {
                                          return (f1.lastModified() < f2.lastModified()) ? -1 : ((f1.lastModified() == f2.lastModified()) ? 0 : 1);
                                      }
                                  }); 
                      

                      【讨论】:

                        【解决方案20】:

                        还有一种完全不同的方法可能更容易,因为我们不处理大量数字。

                        您无需在检索到所有文件名和 lastModified 日期后对整个数组进行排序,您只需将检索到的每个文件名插入到列表的正确位置即可。

                        你可以这样做:

                        list.add(1, object1)
                        list.add(2, object3)
                        list.add(2, object2)
                        

                        将object2添加到位置2后,它会将object3移动到位置3。

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2016-04-01
                          • 1970-01-01
                          • 2015-11-17
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多