Melhor maneira de arquivos de lista em Java, ordenados por data de modificação?
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());
} });
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
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.