Melhor maneira de arquivos de lista em Java, ordenados por data de modificação?

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu quero começar uma lista de arquivos em um diretório, mas eu quero classificá-lo de tal forma que os arquivos mais antigos são de primeira. Minha solução foi chamar File.listFiles e apenas recorrer a lista com base em File.lastModified, mas eu queria saber se havia uma maneira melhor.

Edit: Minha solução atual, como sugerido, é a utilização de um anônimo Comparador:

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

Solução

Eu acho que sua solução é a única maneira sensata. A única maneira de obter a lista de arquivos é usar File.listFiles () e os estados de documentação que isso não faz nenhuma garantia sobre a ordem dos arquivos devolvidos. Portanto, você precisa escrever uma Comparador que usos File.lastModified () e passar isso, juntamente com o conjunto de arquivos, a Arrays.sort () .

Outras dicas

Isso pode ser mais rápido se você tem muitos arquivos. Este usa o padrão decorar-sort-undecorate para que a data da última modificação de cada arquivo só é buscada uma vez , em vez de cada vez que o algoritmo de ordenação compara dois arquivos. Este potencialmente reduz o número de I / O chamadas de O (n log n) para O (n).

É mais código, porém, assim que isso só deve ser usado se você está preocupado principalmente com a velocidade e é consideravelmente mais rápido na prática (o que eu não tenho verificado).

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;

O que é sobre abordagem semelhante, mas sem o boxe ao longo objetos:

File[] files = directory.listFiles();

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

solução elegante desde Java 8:

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

Ou, se você quer que ele em ordem decrescente, basta inverter isso:

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

Você também pode olhar para Apache Commons IO , ele foi construído em um modificada pela última vez comparador muitas outras utilidades agradáveis ??para trabalhar com arquivos.

Em Java 8:

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

Importações:

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

    }

Se os arquivos que você está de classificação podem ser modificados ou atualizados ao mesmo tempo, a espécie está sendo realizada:


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 estas soluções criar uma estrutura de mapa de dados temporária para salvar fora um último tempo constante modificado para cada arquivo no diretório. A razão que precisamos de fazer isso é que, se seus arquivos estão sendo atualizados ou modificados, enquanto o seu tipo está sendo realizado então o seu comparador estará violando a exigência transitividade do contrato geral da interface de comparação porque os últimos tempos modificados podem estar mudando durante a comparação.

Se, por outro lado, você sabe que os arquivos não serão atualizados ou modificados durante a sua sorte, você pode começar afastado com praticamente qualquer outra resposta submetidos a esta questão.

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

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

Você pode tentar a goiaba encomenda :

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

Você pode usar o Apache LastModifiedFileComparator biblioteca

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

onde listFiles é a coleção de todos os arquivos em ArrayList

Eu vim a este post quando eu estava procurando a mesma questão, mas em android. Eu não digo que esta é a melhor maneira de obter arquivos ordenados por data da última modificação, mas é a maneira mais fácil que eu encontrei ainda.

Abaixo código pode ser útil para alguém -

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
    }

Graças

Há uma maneira muito fácil e conveniente para lidar com o problema sem qualquer comparador extra. código apenas a data modificada para o String com o nome do arquivo, classificá-lo, e depois tira-lo de novo.

Use uma cadeia de comprimento fixo 20, colocar a data modificada (longo) para ele, e encher-se com zeros à esquerda. Em seguida, basta anexar o nome do arquivo para essa string:

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

O que acontece é este aqui:

filename1: C: \ data \ Arq1.html Última modificação: 1532914451455 última modificação 20 dígitos: 00000001532914451455

filename1: C: \ data \ file2.html Última modificação: 1532918086822 última modificação 20 dígitos: 00000001532918086822

transforma filnames para:

filename1: 00000001532914451455C: \ data \ Arq1.html

filename2: 00000001532918086822C: \ data \ file2.html

Você pode, então, apenas uma espécie esta lista.

Tudo que você precisa fazer é tirar os 20 caracteres novamente mais tarde (em Java 8, você pode tira-lo para toda a matriz com apenas uma linha usando a função .replaceAll)

Há também uma maneira completamente diferente, que pode ser ainda mais fácil, já que não lidar com grandes números.

Em vez de classificar a matriz inteira depois de recuperados todos os nomes e datas lastModified, você pode simplesmente inserir cada nome logo depois que você recuperou na posição direita da lista.

Você pode fazê-lo como este:

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

Depois de adicionar object2 para a posição 2, ele vai passar object3 a posição 3.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top