¿La mejor manera de listar archivos en Java, ordenados por fecha de modificación?

StackOverflow https://stackoverflow.com/questions/203030

  •  03-07-2019
  •  | 
  •  

Pregunta

Quiero obtener una lista de archivos en un directorio, pero quiero ordenarlos de modo que los archivos más antiguos sean los primeros. Mi solución fue llamar a File.listFiles y simplemente recurrir a la lista basada en File.lastModified, pero me preguntaba si había una mejor manera.

Editar: mi solución actual, como se sugiere, es usar un Comparador anónimo:

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());
    } });
¿Fue útil?

Solución

Creo que tu solución es la única manera sensata. La única forma de obtener la lista de archivos es usar File.listFiles () y la documentación indica que esto no ofrece ninguna garantía sobre el orden de los archivos devueltos. Por lo tanto, debe escribir un Comparator que utiliza File.lastModified () y pase esto, junto con la matriz de archivos, a Arrays.sort () .

Otros consejos

Esto podría ser más rápido si tienes muchos archivos. Esto utiliza el patrón decorate-sort-undecorate para que la fecha de la última modificación de cada archivo se obtenga solo una vez en lugar de cada vez que el algoritmo de clasificación compare dos archivos. Esto reduce potencialmente el número de llamadas de E / S de O (n log n) a O (n).

Sin embargo, es más código, por lo que solo debe usarse si te preocupa la velocidad y es mucho más rápido en la práctica (que no he comprobado).

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;

¿Qué hay de enfoque similar, pero sin encajonar a los objetos largos:

File[] files = directory.listFiles();

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

Solución elegante desde Java 8:

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

O, si lo quieres en orden descendente, simplemente inviértelo:

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

También puede consultar apache commons IO , se ha creado en último comparador modificado y muchas otras utilidades agradables para trabajar con archivos.

En Java 8:

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

Importaciones:

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

Código:

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

    }

Si los archivos que está ordenando pueden modificarse o actualizarse al mismo tiempo que se realiza la clasificació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;
}


Ambas soluciones crean una estructura de datos de mapas temporales para ahorrar una última vez modificada constante para cada archivo en el directorio. La razón por la que debemos hacer esto es que si sus archivos se actualizan o modifican mientras se realiza su ordenación, su comparador violará el requisito de transitividad del contrato general de la interfaz del comparador porque los últimos tiempos modificados pueden cambiar durante la comparación.

Si, por otro lado, sabe que los archivos no se actualizarán o modificarán durante su clasificación, puede salirse con la suya casi con cualquier otra respuesta enviada a esta pregunta.

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

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

Puede probar guayaba Ordenar :

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

Puede usar Apache LastModifiedFileComparator library

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

donde listFiles es la colección de todos los archivos en ArrayList

Llegué a esta publicación cuando estaba buscando el mismo problema pero en android . No digo que esta sea la mejor manera de ordenar los archivos por fecha de última modificación, pero es la forma más fácil que he encontrado hasta ahora.

El código de abajo puede ser útil para alguien-

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
    }

Gracias

Hay una manera muy fácil y conveniente de manejar el problema sin ningún comparador adicional. Simplemente codifique la fecha de modificación en la Cadena con el nombre del archivo, ordénelo y luego elimínelo nuevamente.

Use una cadena de longitud fija 20, ponga la fecha modificada (larga) en ella y rellene con ceros a la izquierda. Luego simplemente agregue el nombre del archivo a esta cadena:

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

Lo que sucede es esto aquí:

Nombre de archivo 1: C: \ data \ file1.html Última modificación: 1532914451455 Última modificación de 20 dígitos: 00000001532914451455

Nombre de archivo 1: C: \ data \ file2.html Última modificación: 1532918086822 Última modificación de 20 dígitos: 00000001532918086822

transforma los nombres de archivo a:

Nombre de archivo 1: 00000001532914451455C: \ data \ file1.html

Nombre de archivo2: 00000001532918086822C: \ data \ file2.html

Luego puedes ordenar esta lista.

Todo lo que necesitas hacer es eliminar los 20 caracteres más tarde (en Java 8, puedes eliminarlo para toda la matriz con solo una línea usando la función .replaceAll)

También hay una forma completamente diferente que puede ser incluso más fácil, ya que no tratamos con grandes números.

En lugar de ordenar toda la matriz después de recuperar todos los nombres de archivo y las fechas de última modificación, puede insertar cada nombre de archivo solo después de recuperarlo en la posición correcta de la lista.

Puedes hacerlo así:

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

Después de agregar object2 a la posición 2, moverá object3 a la posición 3.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top