Cách tốt nhất để liệt kê các tệp trong Java, được sắp xếp theo Ngày Sửa đổi?


240

Tôi muốn có một danh sách các tập tin trong một thư mục, nhưng tôi muốn sắp xếp nó sao cho các tập tin cũ nhất là đầu tiên. Giải pháp của tôi là gọi File.listFiles và chỉ sử dụng danh sách dựa trên File.lastModified, nhưng tôi tự hỏi liệu có cách nào tốt hơn không.

Chỉnh sửa: Giải pháp hiện tại của tôi, như được đề xuất, là sử dụng Trình so sánh ẩn danh:

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

1
Điều gì với phần "mới dài" này? Tại sao bạn không so sánh bản thân dài? điều đó sẽ tránh cho bạn tạo ra vô số thời gian dài chỉ để đến phương thức so sánh ...
John Gardner

Mã này không biên dịch. phương pháp so sánh mong đợi rằng lợi nhuận là một int thay vì Long.
marcospereira

1
Tôi có phải là người duy nhất xem xét giải pháp này điên rồ không? Bạn đang gọi file.lastModified()một số lượng lớn thời gian. Tốt hơn nên lấy tất cả các ngày đầu tiên và đặt hàng sau, vì vậy file.lastModified()chỉ được gọi một lần cho mỗi tệp.
cprcrack

1
Bạn có thể sử dụng bộ so sánh apache commons:Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
jlunavtgrad

5
Có một giải pháp tốt hơn với Java 8 (xem câu trả lời của viniciussss):Arrays.sort(files, Comparator.comparingLong(File::lastModified));
starbroken

Câu trả lời:


99

Tôi nghĩ rằng giải pháp của bạn là cách hợp lý duy nhất. Cách duy nhất để có được danh sách các tệp là sử dụng File.listFiles () và tài liệu nói rằng điều này không đảm bảo về thứ tự của các tệp được trả về. Do đó, bạn cần phải viết một Trình so sánh sử dụng File.lastModified () và chuyển cái này, cùng với mảng các tệp, đến Arrays.sort () .


Làm cách nào để sửa định dạng ở đây? Có vẻ tốt trong bản xem trước nhưng liên kết thứ 4 bị vặn.
Dan Dyer

1
File.lastModified có thể thay đổi trong khi sắp xếp kết quả cuối cùng trong Lỗi Vi phạm Phương thức so sánh, xem: stackoverflow.com/questions/20431031 Xem stackoverflow.com/a/4248059/314089 để biết giải pháp tốt hơn.
băng giá

48

Điều này có thể nhanh hơn nếu bạn có nhiều tệp. Điều này sử dụng mẫu không sắp xếp trang trí sao cho ngày sửa đổi cuối cùng của mỗi tệp chỉ được tìm nạp một lần thay vì mỗi lần thuật toán sắp xếp so sánh hai tệp. Điều này có khả năng làm giảm số lượng cuộc gọi I / O từ O (n log n) đến O (n).

Tuy nhiên, đó là nhiều mã hơn, vì vậy chỉ nên sử dụng mã này nếu bạn chủ yếu quan tâm đến tốc độ và nó nhanh hơn thực tế (mà tôi chưa kiểm tra).

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;

5
Câu trả lời hay nhất, vì có lẽ đây là người duy nhất ngăn chặn "Lỗi vi phạm phương pháp so sánh" nếu lần cuối thay đổi trong khi sắp xếp?
băng giá

1
Điều này cũng nên được sử dụng khi bạn lo lắng về việc không nhận được IllegalArgumentException do vi phạm phương pháp so sánh. Phương pháp sử dụng Map sẽ thất bại nếu có nhiều hơn một tệp có cùng giá trị LastModified dẫn đến bỏ sót các tệp này. Điều này chắc chắn nên là một câu trả lời được chấp nhận.
phát triển Android

44

Giải pháp tao nhã kể từ Java 8:

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

Hoặc, nếu bạn muốn nó theo thứ tự giảm dần, chỉ cần đảo ngược nó:

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

2
Đây thực sự là giải pháp dễ nhất. Đối với danh sách:files.sort(Comparator.comparingLong(File::lastModified));
starbroken

@starbroken Giải pháp của bạn không hoạt động nếu các tệp là một mảng đơn giản, như Tệp [], được trả về bởi thư mục.listFiles ().
viniciussss

@starbroken Để giải pháp của bạn hoạt động, người ta cần sử dụng ArrayList<File> files = new ArrayList<File>(Arrays.asList(directory.listFiles())), điều đó không dễ hơn chỉ File[] files = directory.listFiles().
viniciussss

Vâng tôi đồng ý với bạn. Nếu bạn có một mảng các tập tin, không có lý do để tạo một danh sách. (Nếu kỳ ai, đó là thêm ' ArrayList<File>(...)trong bình luận viniciussss là cần thiết để có được một danh sách có thể thay đổi mà có thể được sắp xếp.) Tôi tìm thấy thread này tìm kiếm một cách để sắp xếp một danh sách các tập tin. Vì vậy, tôi chỉ cần thêm mã đó để mọi người có thể sao chép mã nếu họ có danh sách.
phá vỡ

Các Comparatorlớp học không có bất kỳ lời gọi phương thứccomparingLong
zeleven

37

Cách tiếp cận tương tự, nhưng không có quyền anh với các vật thể dài:

File[] files = directory.listFiles();

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

Đây dường như chỉ là API 19+.
Gábor

4
Sử dụng return Long.valueOf (f1.lastModified ()). SoToTo (f2.lastModified ()); thay vì cho api thấp hơn.
Martin Sykes

25

Bạn cũng có thể nhìn vào apache commons IO , nó có một bộ so sánh được sửa đổi lần cuối và nhiều tiện ích tốt đẹp khác để làm việc với các tệp.


5
Có một lỗi lạ trong javadoc với giải pháp này, bởi vì javadoc nói rằng sử dụng "LastModifiedFileComparator.LASTMODIFIED_COMPARATOR.sort (list);" để sắp xếp danh sách, nhưng LASTMODIFIED_COMPARATOR được khai báo là "Trình so sánh <Tệp>", do đó, nó không hiển thị bất kỳ phương thức "sắp xếp" nào.
Tristan

4
Sử dụng nó như thế này: link
cleroo

1
File.lastModified có thể thay đổi trong khi sắp xếp kết quả cuối cùng trong Lỗi Vi phạm Phương thức so sánh, xem: stackoverflow.com/questions/20431031 Xem stackoverflow.com/a/4248059/314089 để biết giải pháp tốt hơn.
băng giá

1
tình yêu apache commons, đã tiết kiệm rất nhiều thời gian,
redDevil

16

Trong Java 8:

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


13

Nhập khẩu:

org.apache.commons.io.comparator.LastModifiedFileComparator

Cộng đồng Apache

Mã số:

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

    }

Nó không rõ ràng ngay lập tức từ đâu LastModifiedFileComparator.LASTMODIFIED_COMPARATOR được thực hiện. Có lẽ thêm liên kết đến apache commons io sẽ giúp.
băng thông rộng

Xong, Cảm ơn băng thông rộng
Balaji Boggaram Ramanarayan

10

Nếu các tệp bạn đang sắp xếp có thể được sửa đổi hoặc cập nhật cùng lúc thì việc sắp xếp đang được thực hiện:


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


Cả hai giải pháp này đều tạo ra cấu trúc dữ liệu bản đồ tạm thời để tiết kiệm thời gian sửa đổi liên tục cuối cùng cho mỗi tệp trong thư mục. Lý do chúng tôi cần làm điều này là nếu các tệp của bạn đang được cập nhật hoặc sửa đổi trong khi sắp xếp của bạn đang được thực hiện thì bộ so sánh của bạn sẽ vi phạm yêu cầu về tính chuyển đổi của hợp đồng chung của giao diện so sánh vì thời gian sửa đổi cuối cùng có thể thay đổi trong quá trình so sánh.

Mặt khác, nếu bạn biết rằng các tệp sẽ không được cập nhật hoặc sửa đổi trong quá trình sắp xếp của bạn, bạn có thể thoát khỏi khá nhiều câu trả lời khác được gửi cho câu hỏi này, trong đó tôi là một phần:

Java 8+ (Không sửa đổi đồng thời trong khi sắp xếp)

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

Lưu ý: Tôi biết bạn có thể tránh việc dịch sang và từ các đối tượng Tệp trong ví dụ trên bằng cách sử dụng Tệp :: getLastModifiedTime api trong hoạt động luồng được sắp xếp, tuy nhiên, sau đó bạn cần xử lý các ngoại lệ IO đã kiểm tra bên trong lambda của mình. . Tôi muốn nói rằng hiệu suất đủ quan trọng đến mức bản dịch không được chấp nhận thì tôi sẽ xử lý IOException đã kiểm tra trong lambda bằng cách tuyên truyền nó dưới dạng UncheckedIOException hoặc tôi sẽ từ bỏ các tệp api hoàn toàn và chỉ xử lý các đối tượng Tệp:

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

2
public String[] getDirectoryList(String path) {
    String[] dirListing = null;
    File dir = new File(path);
    dirListing = dir.list();

    Arrays.sort(dirListing, 0, dirListing.length);
    return dirListing;
}

1
Điều này không thực sự sắp xếp vào tài sản sửa đổi ngày được đề cập trong câu hỏi. Hàm sort sẽ sử dụng thứ tự tự nhiên của đối tượng File là từ điển phụ thuộc hệ thống vào tên đường dẫn .
Matt Chan

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

nơi listFilestập hợp tất cả các tệp trong ArrayList


1

Bạn có thể thử đặt hàng ổi :

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

1

Bạn có thể sử dụng thư viện 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 + "");
        }

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

0

Tôi đã đến bài viết này khi tôi đang tìm kiếm cùng một vấn đề nhưng trong android. Tôi không nói rằng đây là cách tốt nhất để nhận các tệp được sắp xếp trước ngày sửa đổi gần đây, nhưng đó là cách dễ nhất tôi tìm thấy.

Mã dưới đây có thể hữu ích cho ai đó-

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
    }

Cảm ơn


Nhưng ai sắp xếp?
DAB

ở phần khởi động của forvòng lặp bạn có thể thấy tôi đã lấy list.length-1tối đa i >=0mà chỉ đơn giản lặp bạn theo thứ tự ngược.
Hirdesh Vishwdewa

0

Có một cách rất dễ dàng và thuận tiện để xử lý vấn đề mà không cần bất kỳ bộ so sánh bổ sung nào. Chỉ cần mã ngày sửa đổi vào Chuỗi với tên tệp, sắp xếp nó và sau đó loại bỏ nó một lần nữa.

Sử dụng Chuỗi có độ dài cố định 20, đặt ngày sửa đổi (dài) vào đó và điền vào các số 0 đứng đầu. Sau đó, chỉ cần nối tên tệp vào chuỗi này:

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

Điều gì xảy ra ở đây:

Tên tệp1: C: \ data \ file1.html Sửa đổi lần cuối: 1532914451455 20 chữ số được sửa đổi lần cuối: 00000001532914451455

Tên tệp1: C: \ data \ file2.html Sửa đổi lần cuối: 1532918086822 20 chữ số được sửa đổi lần cuối: 00000001532918086822

biến đổi tên tệp thành:

Tên tệp1: 00000001532914451455C: \ data \ file1.html

Tên tệp2: 00000001532918086822C: \ data \ file2.html

Sau đó bạn có thể sắp xếp danh sách này.

Tất cả những gì bạn cần làm là tước lại 20 ký tự sau (trong Java 8, bạn có thể tách nó cho toàn bộ Mảng chỉ bằng một dòng bằng cách sử dụng hàm .replaceAll)


-1

Ngoài ra còn có một cách hoàn toàn khác có thể dễ dàng hơn nữa, vì chúng ta không đối phó với số lượng lớn.

Thay vì sắp xếp toàn bộ mảng sau khi bạn lấy tất cả tên tệp và ngày cuối cùng, bạn chỉ có thể chèn từng tên tệp duy nhất ngay sau khi bạn lấy nó ở đúng vị trí của danh sách.

Bạn có thể làm như thế này:

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

Sau khi bạn thêm object2 vào vị trí 2, nó sẽ di chuyển object3 sang vị trí 3.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.