날짜를 기준으로 정렬하여 Java로 파일을 나열하는 가장 좋은 방법은 무엇입니까?


240

디렉토리에 파일 목록을 가져오고 싶지만 가장 오래된 파일이 먼저 정렬되도록 정렬하고 싶습니다. 내 솔루션은 File.listFiles를 호출하고 File.lastModified를 기반으로 목록을 작성하는 것이었지만 더 나은 방법이 있는지 궁금했습니다.

편집 : 내 현재 솔루션은 제안 된대로 익명의 비교기를 사용하는 것입니다.

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
이것의 "새로운 긴"부분은 무엇입니까? 왜 그냥 Longs 자체를 비교하지 않습니까? 그냥 ... compareTo 메소드에 도착하는 갈망의 톤을 만들지 않도록 것이라고
존 가드너

이 코드는 컴파일되지 않습니다. 비교 메소드는 리턴이 Long 대신 int 인 것으로 예상합니다.
marcospereira

1
이 솔루션을 제정신으로 생각하는 유일한 사람입니까? 당신은 file.lastModified()많은 시간을 부르고 있습니다. 모든 날짜를 먼저 얻은 다음 나중에 주문하는 file.lastModified()것이 좋습니다. 따라서 파일 당 한 번만 호출됩니다.
cprcrack

1
Apache Commons Comparator를 사용할 수 있습니다.Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
jlunavtgrad

5
Java 8에는 더 나은 솔루션이 있습니다 (viniciussss 답변 참조).Arrays.sort(files, Comparator.comparingLong(File::lastModified));
starbroken

답변:


99

귀하의 솔루션이 합리적인 방법이라고 생각합니다. 파일 목록을 얻는 유일한 방법은 File.listFiles () 를 사용 하는 것이며 문서는 반환 된 파일의 순서를 보증하지 않습니다. 따라서 File.lastModified () 를 사용 하는 Comparator 를 작성하고 이를 파일 배열과 함께 Arrays.sort ()에 전달해야 합니다.


여기에서 서식을 어떻게 수정합니까? 미리보기에서 잘 보이지만 네 번째 링크는 고정되어 있습니다.
Dan Dyer

1
비교 방법 위반 오류에 최종 결과를 정렬하는 동안, 참조 File.lastModified가 변경 될 수 있습니다 : stackoverflow.com/questions/20431031 참조 stackoverflow.com/a/4248059/314089을 가능한 더 나은 솔루션을.
icyerasor 2016 년

48

파일이 많은 경우 더 빠를 수 있습니다. 이것은 sortate-sort-undecorate 패턴을 사용하므로 정렬 알고리즘이 두 파일을 비교할 때마다가 아니라 각 파일의 마지막 수정 날짜를 한 번만 가져옵니다 . 이는 잠재적으로 O (n log n)에서 O (n)으로의 I / O 호출 수를 줄입니다.

그러나 더 많은 코드이므로 속도에 주로 관심이 있고 실제로 확인하지 않은 경우 훨씬 빠릅니다.

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
정렬 중에 lastModified가 변경되면 "비교 방법 위반 오류"를 방지 할 수있는 유일한 방법 일 것입니다.
icyerasor

1
비교 메소드 위반으로 인해 IllegalArgumentException이 발생하지 않을 경우에도 사용해야합니다. lastModified 값이 동일한 파일이 둘 이상 있으면 Map을 사용하는 방법이 실패하여 해당 파일이 생략됩니다. 이것은 분명히 받아 들여질만한 대답이어야합니다.
Android 개발자

44

Java 8 이후의 우아한 솔루션 :

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

또는 내림차순으로 원하면 뒤집으십시오.

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

2
이것이 가장 쉬운 솔루션입니다. 목록의 경우 :files.sort(Comparator.comparingLong(File::lastModified));
starbroken

@starbroken 파일이 File []과 같이 directory.listFiles ()에 의해 반환 된 간단한 배열 인 경우 솔루션이 작동하지 않습니다.
viniciussss

@starbroken 솔루션이 제대로 작동하려면 사용 ArrayList<File> files = new ArrayList<File>(Arrays.asList(directory.listFiles()))하기 만하면 File[] files = directory.listFiles()됩니다.
viniciussss

그래 나도 너와 같은 생각이야. 파일 배열이 있으면 목록을 만들 이유가 없습니다. (누군가 궁금하면 ArrayList<File>(...)viniciussss 주석의 '추가' 가 정렬 가능한 가변 목록을 얻는 데 필요합니다.)이 스레드는 파일 목록을 정렬하는 방법을 찾고 있습니다. 그래서 방금 코드를 추가하여 사람들이 목록이있는 경우 간단히 복사 할 수 있습니다.
스타 브로큰

Comparator클래스에는 메소드 호출이 없습니다comparingLong
zeleven

37

비슷한 접근 방식에 관한 것이지만 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());
    }
});

API 19 이상인 것 같습니다.
Gábor

4
return Long.valueOf (f1.lastModified ())를 사용하십시오. compareTo (f2.lastModified ()); 대신 더 낮은 API를 위해.
Martin Sykes

25

또한 apache commons IO를 살펴볼 수 있으며 마지막으로 수정 된 비교기 와 파일 작업을위한 많은 다른 유용한 유틸리티가 있습니다.


5
javadoc이 "LastModifiedFileComparator.LASTMODIFIED_COMPARATOR.sort (list);"를 사용한다고 말했기 때문에이 솔루션과 함께 javadoc에 이상한 오류가 있습니다. 목록을 정렬하지만 LASTMODIFIED_COMPARATOR는 "Comparator <File>"으로 선언되므로 "sort"메소드가 노출되지 않습니다.
Tristan

4
다음과 같이 사용하십시오 : link
cleroo

1
비교 방법 위반 오류에 최종 결과를 정렬하는 동안, 참조 File.lastModified가 변경 될 수 있습니다 : stackoverflow.com/questions/20431031 참조 stackoverflow.com/a/4248059/314089을 가능한 더 나은 솔루션을.
icyerasor 2016 년

1
많은 시간을 절약 한 아파치 커먼즈를 사랑하십시오
redDevil

16

자바 8 :

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


13

수입 :

org.apache.commons.io.comparator.LastModifiedFileComparator

아파치 커먼즈

코드 :

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를 어디에서 가져 왔는지 분명하지 않습니다. 어쩌면 apache commons io에 링크를 추가 하면 도움이 될 것입니다.
광대역

완료, 덕분에 광대역
발라지 Boggaram Ramanarayan에게

10

정렬중인 파일을 동시에 수정하거나 업데이트 할 수있는 경우 정렬을 수행하는 중입니다.


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

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


이 두 가지 솔루션 모두 디렉토리의 각 파일에 대해 마지막으로 수정 된 시간을 절약하기 위해 임시 맵 데이터 구조를 만듭니다. 이를 수행해야하는 이유는 정렬이 수행되는 동안 파일이 업데이트되거나 수정되는 경우 비교 중에 마지막 수정 시간이 변경 될 수 있기 때문에 비교기가 비교기 인터페이스의 일반 계약의 전이 요구 사항을 위반하기 때문입니다.

반면에 정렬 중에 파일이 업데이트되거나 수정되지 않는다는 것을 알고 있다면이 질문에 제출 된 다른 답변으로 거의 벗어날 수 있습니다.

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

참고 : 정렬 된 스트림 작업에서 Files :: getLastModifiedTime api를 사용하여 위 예제에서 File 객체와의 변환을 피할 수 있다는 것을 알고 있지만 람다 내에서 확인 된 IO 예외를 처리해야합니다. . 번역이 허용 할 수 없을 정도로 성능이 중요하다면 Lambda에서 확인 된 IOException을 UncheckedIOException으로 전파하여 처리하거나 파일을 완전히 포기하고 File 객체 만 처리합니다.

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
이것은 실제로 질문에 언급 된 날짜 수정 속성에 따라 정렬되지 않습니다. 정렬 함수는 경로 이름시스템 종속 사전 형인 File 객체의 자연 순서를 사용합니다 .
Matt Chan

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

listFilesArrayList의 모든 파일 모음은 어디에 있습니까?


1

당신은 구아바 시도 할 수 있습니다 주문을 :

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 라이브러리를 사용할 수 있습니다

 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

나는 같은 문제를 찾고 있었지만이 게시물에 왔습니다 android. 나는 이것이 마지막으로 수정 된 날짜별로 정렬 된 파일을 얻는 가장 좋은 방법이라고 말하지는 않지만 내가 찾은 가장 쉬운 방법입니다.

아래 코드는 누군가에게 도움이 될 수 있습니다.

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
    }

감사


그러나 누가 정렬합니까?
DAB

의 초기화 부분에 for루프 당신이 내가 촬영 한 볼 수 있습니다 list.length-1개까지 i >=0있는 단순히으로 반복하면 역순으로한다.
Hirdesh Vishwdewa

0

별도의 비교기를 사용하지 않고 문제를 처리 할 수있는 매우 쉽고 편리한 방법이 있습니다. 수정 한 날짜를 파일 이름으로 문자열에 코딩하고 정렬 한 다음 나중에 다시 제거하십시오.

고정 길이 20의 문자열을 사용하고 수정 된 날짜 (긴)를 넣고 앞에 0을 채 웁니다. 그런 다음 파일 이름을이 문자열에 추가하십시오.

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

여기서 일어나는 일은 :

파일 이름 1 : C : \ data \ file1.html 마지막 수정 : 1532914451455 마지막 수정 20 자리 : 00000001532914451455

파일 이름 1 : C : \ data \ file2.html 마지막 수정 : 1532918086822 마지막 수정 20 자리 : 00000001532918086822

파일 이름을 다음으로 변환합니다.

파일 이름 1 : 00000001532914451455C : \ data \ file1.html

파일 이름 2 : 00000001532918086822C : \ data \ file2.html

그런 다음이 목록을 정렬하면됩니다.

Java 문자 8에서는 .replaceAll 함수를 사용하여 한 줄만으로 전체 Array에 대해 20자를 제거 할 수 있습니다.


-1

우리는 많은 수를 다루지 않기 때문에 훨씬 더 쉬운 완전히 다른 방법이 있습니다.

모든 파일 이름과 lastModified 날짜를 검색 한 후 전체 배열을 정렬하는 대신 목록의 올바른 위치에서 검색 한 직후에 모든 단일 파일 이름을 삽입 할 수 있습니다.

다음과 같이 할 수 있습니다.

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

object2를 위치 2에 추가하면 object3이 위치 3으로 이동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.