Java'da dosyaları Değiştirilme Tarihine göre sıralamanın en iyi yolu?


240

Bir dizindeki dosyaların bir listesini almak istiyorum, ancak en eski dosyalar ilk olacak şekilde sıralamak istiyorum. Benim çözüm File.listFiles aramak ve sadece File.lastModified dayalı liste başvurmak oldu, ama daha iyi bir yolu olup olmadığını merak ediyordum.

Düzenleme: Benim mevcut çözüm, önerildiği gibi, anonim bir karşılaştırıcı kullanmaktır:

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
bunun "yeni uzun" kısmı nedir? neden sadece özleri kendiniz karşılaştırmıyorsunuz? Bu sadece CompareTo yöntemine ulaşmak için tonlarca uzun ürün yaratmanızı önler ...
John Gardner

Bu kod derlenmez. karşılaştırma yöntemleri, dönüşün Long yerine int olmasını bekler.
marcospereira

1
Bu çözümü delice gören tek kişi ben miyim? Sen çok file.lastModified()kez çağırıyorsun . Öncelikle tüm tarihleri ​​al ve daha sonra sipariş ver, böylece file.lastModified()dosya başına sadece bir kez çağrılır.
cprcrack

1
Apache ortak karşılaştırıcı kullanabilirsiniz:Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
jlunavtgrad

5
Java 8 ile daha iyi bir çözüm var (viniciussss cevabına bakınız):Arrays.sort(files, Comparator.comparingLong(File::lastModified));
starbroken

Yanıtlar:


99

Bence çözümünüz tek mantıklı yol. Dosya listesini almanın tek yolu File.listFiles () kullanmaktır ve belgeler, bunun döndürülen dosyaların sırası hakkında hiçbir garanti vermediğini belirtir. Bu nedenle File.lastModified () kullanan bir Comparator yazmanız ve bunu dosya dizisiyle birlikte Arrays.sort () öğesine iletmeniz gerekir .


Biçimlendirmeyi burada nasıl düzeltebilirim? Önizlemede iyi görünüyor ancak 4. bağlantı vidalanmış.
Dan Dyer

1
Bir Karşılaştırma Yöntemi İhlali Hata sonuçta sıralama yaparken, bkz File.lastModified değişebilir: stackoverflow.com/questions/20431031 Bkz stackoverflow.com/a/4248059/314089 olası daha iyi bir çözüm için.
icyerasor

48

Çok sayıda dosyanız varsa bu daha hızlı olabilir. Bu, decorate-sort-undecorate desenini kullanır, böylece her dosyanın son değiştirilme tarihi , sıralama algoritmasının iki dosyayı her karşılaştırışından ziyade yalnızca bir kez getirilir . Bu potansiyel olarak O (n log n) 'den O (n)' ye G / Ç çağrılarının sayısını azaltır.

Daha fazla kod olsa da, bu sadece hız ile ilgileniyorsanız ve pratikte (daha önce kontrol etmedim) ölçülebilir derecede daha hızlıysa kullanılmalıdır.

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
En iyi cevap, muhtemelen sıralama sırasında lastModified değişirse bir "Karşılaştırma Yöntemi İhlali Hatası" önleyen sadece biri mi?
icyerasor

1
Bu, karşılaştırma yöntemi ihlali nedeniyle IllegalArgumentException'ı almayla ilgili endişeleriniz olduğunda da kullanılmalıdır. MapModified yöntemi, aynı lastModified değerine sahip birden fazla dosya varsa ve bu dosyaların atlanmasına neden olacak şekilde başarısız olursa yöntem başarısız olur. Bu kesinlikle kabul edilmiş bir cevap olmalıdır.
Android geliştiricisi

44

Java 8'den beri zarif çözüm:

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

Ya da, azalan sırada istiyorsanız, tersine çevirin:

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

2
Bu gerçekten en kolay çözümdür. Listeler için:files.sort(Comparator.comparingLong(File::lastModified));
starbroken

@starbroken Dosyalar File [] gibi, directory.listFiles () tarafından döndürülen basit bir dizi ise çözümünüz çalışmaz.
viniciussss

@starbroken Çözümünüzün çalışması için, bir kişinin kullanması gerekiyor ArrayList<File> files = new ArrayList<File>(Arrays.asList(directory.listFiles())), bu sadece kolay değil File[] files = directory.listFiles().
viniciussss

Evet ben size katılıyorum. Bir dizi dosyanız varsa, liste oluşturmak için bir neden yoktur. (Herkes merak ederse, ArrayList<File>(...)sıralanabilir bir değiştirilebilir liste almak için viniciussss yorumda bu 'ek' gereklidir.) Bu konu dosyaları listesini sıralamak için bir yol arıyor bulundu. Bu yüzden sadece insanlar da listeleri var ise kopyalamak böylece bu kodu ekledi.
starbroken

ComparatorSınıf herhangi bir yöntem çağrısı yokcomparingLong
zeleven

37

Benzer yaklaşım hakkında, ama Uzun nesnelere boks yapmadan:

File[] files = directory.listFiles();

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

Bu sadece API 19+ gibi görünüyor.
Gabor

4
Return Long.valueOf (f1.lastModified ()) kullanın. CompareTo (f2.lastModified ()); bunun yerine alt apiler için.
Martin Sykes

25

Ayrıca bakmak olabilir apache commons IO , bu bir inşa etti son düzenleme karşılaştırıcı dosyaları ile çalışmak için ve diğer birçok güzel araçlardan.


5
Javadoc'ta bu çözümde garip bir hata var, çünkü javadoc "LastModifiedFileComparator.LASTMODIFIED_COMPARATOR.sort (list);" listeyi sıralamak için, ancak LASTMODIFIED_COMPARATOR "Karşılaştırıcı <Dosya>" olarak bildirildiğinden herhangi bir "sıralama" yöntemi gösterilmez.
Tristan

4
Şunun

1
Bir Karşılaştırma Yöntemi İhlali Hata sonuçta sıralama yaparken, bkz File.lastModified değişebilir: stackoverflow.com/questions/20431031 Bkz stackoverflow.com/a/4248059/314089 olası daha iyi bir çözüm için.
icyerasor

1
çok zaman kazandıran apache commons seviyorum,
redDevil

16

Java 8'de:

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


13

İthalat:

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

Kod:

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'un nereden alındığı anında net değil. Belki apache ortaklarına bağlantı eklemek yardımcı olabilir.
geniş bant

Bitti, Teşekkürler geniş bant
Balaji Boggaram Ramanarayan

10

Sıralama yaptığınız dosyalar, sıralama yapılırken aynı anda değiştirilebilir veya güncellenebilirse:


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


Bu çözümlerin her ikisi de, dizindeki her dosya için son değiştirilme zamanını sabit tutmak için geçici bir harita veri yapısı oluşturur. Bunu yapmamızın nedeni, sıralamanız yapılırken dosyalarınız güncelleniyor veya değiştiriliyorsa, karşılaştırıcı sırasında son değiştirilen zamanlar değişebileceğinden, karşılaştırıcınız karşılaştırıcı arabiriminin genel sözleşmesinin geçerlilik gereksinimini ihlal edecektir.

Öte yandan, sıralama sırasında dosyaların güncellenmeyeceğini veya değiştirilmeyeceğini biliyorsanız, kısmi olduğum bu soruya gönderilen hemen hemen tüm diğer yanıtlardan kurtulabilirsiniz:

Java 8+ (Sıralama sırasında eşzamanlı değişiklik yok)

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

Not: Sıralı akış işleminde Files :: getLastModifiedTime api'yi kullanarak yukarıdaki örnekteki Dosya nesnelerine ve bu nesnelerden çeviriden kaçınabileceğinizi biliyorum , ancak lambda içinde her zaman bir ağrı olan kontrol edilen IO istisnalarıyla uğraşmanız gerekir. . Performansın çevirinin kabul edilemez olduğu kadar kritik olması durumunda, ya bir UncheckedIOException olarak yayılarak lambda'daki kontrol edilen IOException ile başa çıkacağımı ya da Files api'den tamamen vazgeçip sadece File nesneleriyle uğraşacağımı söyleyebilirim:

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
Bu aslında soruda belirtilen tarih değiştirilen özelliği sıralamaz. Sıralama işlevi , yol adında sisteme bağlı sözlükbilimi olan File nesnesinin doğal sırasını kullanır .
Matt Chan

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

listFilesArrayList'teki tüm dosyaların koleksiyonu nerede


1

Guava Sipariş deneyebilirsiniz :

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

Apache LastModifiedFileComparator kütüphanesini kullanabilirsiniz

 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

Ben aynı konu için arama yaparken bu yazı geldi ama içinde android. Bu, son değiştirilme tarihine göre sıralanmış dosyaları almanın en iyi yolu olduğunu söylemiyorum, ancak henüz bulduğum en kolay yol.

Aşağıdaki kod birisi için yararlı olabilir.

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
    }

Teşekkürler


Ama sıralama kimde?
DAB

paraflarlar kısmında fordöngü i almış görebilirsiniz list.length-1kadar i >=0hangi basitçe yinelerler Eğer ters sırada.
Hirdesh Vishwdewa

0

Sorunu ekstra bir karşılaştırıcı olmadan ele almanın çok kolay ve kullanışlı bir yolu vardır. Değiştirilen tarihi dosya adıyla Dize olarak kodlayın, sıralayın ve daha sonra tekrar kesin.

Sabit uzunlukta 20 bir String kullanın, değiştirilen tarihi (uzun) içine koyun ve baştaki sıfırlarla doldurun. Sonra sadece bu dizeye dosya adını ekleyin:

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

Burada olan şu:

Dosyaadı1: C: \ data \ file1.html Son Değiştirme Tarihi: 1532914451455 Son Değiştirme Tarihi 20 Rakam: 00000001532914451455

Dosyaadı1: C: \ data \ file2.html Son Değiştirme Tarihi: 1532918086822 Son Değiştirme Tarihi 20 Rakam: 00000001532918086822

dosya adlarını şu biçime dönüştürür:

Dosyaadı1: 00000001532914451455C: \ data \ file1.html

Dosyaadı2: 00000001532918086822C: \ data \ file2.html

Daha sonra bu listeyi sıralayabilirsiniz.

Yapmanız gereken tek şey 20 karakteri daha sonra tekrar şeritlendirmektir (Java 8'de .replaceAll işlevini kullanarak tüm Array için tek bir satırla şeritleyebilirsiniz)


-1

Büyük rakamlarla uğraşmadığımız için daha da kolay olabilecek tamamen farklı bir yol da var.

Tüm dosya adlarını ve lastModified tarihleri ​​aldıktan sonra dizinin tamamını sıralamak yerine, her bir dosya adını listenin doğru konumuna getirdikten hemen sonra ekleyebilirsiniz.

Bunu şu şekilde yapabilirsiniz:

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

Nesne2'yi konum 2'ye ekledikten sonra, nesne3'ü konum 3'e taşır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.