Domanda

Voglio ottenere un elenco di file in una directory, ma voglio ordinarlo in modo tale che i file più vecchi siano i primi. La mia soluzione era quella di chiamare File.listFiles e semplicemente ricorrere all'elenco basato su File.lastModified, ma mi chiedevo se ci fosse un modo migliore.

Modifica: la mia soluzione attuale, come suggerito, è utilizzare un comparatore anonimo:

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());
    } });
È stato utile?

Soluzione

Penso che la tua soluzione sia l'unico modo sensato. L'unico modo per ottenere l'elenco dei file è utilizzare File.listFiles () e la documentazione afferma che ciò non fornisce alcuna garanzia sull'ordine dei file restituiti. Pertanto è necessario scrivere un Comparator che utilizza File.lastModified () e passa questo, insieme all'array di file, a Arrays.sort () .

Altri suggerimenti

Questo potrebbe essere più veloce se hai molti file. Questo utilizza il modello decorate-ordina-undecorate in modo che la data dell'ultima modifica di ciascun file venga recuperata solo una volta anziché ogni volta che l'algoritmo di ordinamento confronta due file. Ciò potenzialmente riduce il numero di chiamate I / O da O (n log n) a O (n).

Tuttavia, è più codice, quindi dovrebbe essere usato solo se sei principalmente interessato alla velocità ed è misurabile in pratica in modo più veloce (cosa che non ho verificato).

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;

Qual è l'approccio simile, ma senza boxe per gli oggetti 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());
    }
});

Soluzione elegante da Java 8:

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

Oppure, se lo vuoi in ordine decrescente, basta invertirlo:

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

Potresti anche guardare apache commons IO , ha un ultimo comparatore modificato e molte altre belle utilità per lavorare con i file.

In Java 8:

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

Importazioni:

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

Codice:

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

    }

Se i file che stai ordinando possono essere modificati o aggiornati contemporaneamente l'ordinamento viene eseguito:


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


Entrambe queste soluzioni creano una struttura di dati della mappa temporanea per salvare un tempo di ultima modifica costante per ogni file nella directory. La ragione per cui dobbiamo fare questo è che se i tuoi file vengono aggiornati o modificati mentre il tuo ordinamento viene eseguito, il tuo comparatore violerà i requisiti di transitività del contratto generale dell'interfaccia del comparatore perché gli ultimi tempi modificati potrebbero cambiare durante il confronto.

Se, d'altra parte, sai che i file non verranno aggiornati o modificati durante il tuo ordinamento, puoi scappare praticamente con qualsiasi altra risposta inviata a questa domanda.

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

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

Puoi provare guava Ordine :

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

Puoi usare Apache LastModifiedFileComparator libreria

 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 + "");
        }
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;
}
Collections.sort(listFiles, new Comparator<File>() {
        public int compare(File f1, File f2) {
            return Long.compare(f1.lastModified(), f2.lastModified());
        }
    });

dove listFiles è la raccolta di tutti i file in ArrayList

Sono arrivato a questo post mentre cercavo lo stesso problema ma in android . Non dico che questo è il modo migliore per ottenere file ordinati in base alla data dell'ultima modifica, ma è il modo più semplice che ho ancora trovato.

Il codice seguente può essere utile a qualcuno-

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
    }

Grazie

Esiste un modo molto semplice e conveniente per gestire il problema senza alcun comparatore aggiuntivo. Basta codificare la data modificata nella stringa con il nome file, ordinarla e successivamente rimuoverla di nuovo.

Usa una stringa di lunghezza fissa 20, inserisci la data modificata (lunga) e riempila con zeri iniziali. Quindi aggiungi il nome file a questa stringa:

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

Quello che succede è questo qui:

Nome file1: C: \ data \ file1.html Ultima modifica: 1532914451455 Ultima cifra 20 cifre: 00000001532914451455

Nome file1: C: \ data \ file2.html Ultima modifica: 1532918086822 Ultima cifra 20 cifre: 00000001532918086822

trasforma i nomi dei file in:

Nome file1: 00000001532914451455C: \ data \ file1.html

Nome file2: 00000001532918086822C: \ data \ file2.html

È quindi possibile ordinare questo elenco.

Tutto quello che devi fare è rimuovere nuovamente i 20 caratteri in un secondo momento (in Java 8, puoi rimuoverlo per l'intero array con una sola riga usando la funzione .replaceAll)

Esiste anche un modo completamente diverso che potrebbe essere ancora più semplice, poiché non ci occupiamo di grandi numeri.

Invece di ordinare l'intero array dopo aver recuperato tutti i nomi file e le date lastModified, puoi semplicemente inserire ogni singolo nome file subito dopo averlo recuperato nella posizione corretta dell'elenco.

Puoi farlo in questo modo:

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

Dopo aver aggiunto object2 alla posizione 2, sposta object3 nella posizione 3.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top