วิธีที่ดีที่สุดในการแสดงรายการไฟล์ใน 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 ...
จอห์นการ์ดเนอร์

รหัสนี้ไม่ได้รวบรวม วิธีการเปรียบเทียบคาดหวังว่าผลตอบแทนเป็น int แทนที่จะเป็น Long
marcospereira

1
ฉันเป็นคนเดียวที่เห็นว่าการแก้ปัญหานี้เป็นบ้า? คุณกำลังเรียกfile.lastModified()ครั้งใหญ่ ดีกว่ารับวันที่ทั้งหมดก่อนและสั่งซื้อในภายหลังเพื่อที่file.lastModified()จะถูกเรียกเพียงครั้งเดียวต่อไฟล์
cprcrack

1
คุณสามารถใช้ apache คอมมอนเรเตอร์เปรียบเทียบ:Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
jlunavtgrad

5
มีทางออกที่ดีกว่ากับ Java 8 (ดู viniciussss คำตอบ):Arrays.sort(files, Comparator.comparingLong(File::lastModified));
starbroken

คำตอบ:


99

ฉันคิดว่าทางออกของคุณเป็นวิธีที่สมเหตุสมผลเท่านั้น วิธีเดียวที่จะได้รับรายชื่อไฟล์คือการใช้File.listFiles ()และเอกสารประกอบระบุว่าสิ่งนี้ไม่รับประกันว่าจะส่งคืนลำดับของไฟล์ ดังนั้นคุณต้องเขียนเปรียบเทียบที่ใช้File.lastModified ()และผ่านนี้พร้อมกับอาร์เรย์ของไฟล์เพื่อArrays.sort ()


ฉันจะแก้ไขการจัดรูปแบบที่นี่ได้อย่างไร ดูดีในหน้าตัวอย่าง แต่ลิงค์ที่ 4 ถูกทำให้เป็นเกลียว
Dan Dyer

1
File.lastModified อาจเปลี่ยนแปลงในขณะที่การเรียงลำดับผลลัพธ์สุดท้ายในข้อผิดพลาดการละเมิดวิธีการเปรียบเทียบดู: stackoverflow.com/questions/20431031ดูstackoverflow.com/a/4248059/314089เพื่อหาทางออกที่ดีกว่า
icyerasor

48

อาจเร็วกว่านี้หากคุณมีไฟล์จำนวนมาก สิ่งนี้ใช้รูปแบบการตกแต่งเรียงลำดับไม่ได้เพื่อให้วันที่แก้ไขล่าสุดของแต่ละไฟล์ถูกเรียกเพียงครั้งเดียวมากกว่าทุกครั้งที่อัลกอริทึมการเรียงลำดับเปรียบเทียบสองไฟล์ สิ่งนี้อาจลดจำนวนการโทร I / O จาก O (n log n) เป็น O (n)

มันเป็นโค้ดที่มากกว่านั้นดังนั้นควรใช้เฉพาะเมื่อคุณกังวลเรื่องความเร็วเป็นหลักและเร็วกว่าในการใช้งานจริง (ซึ่งฉันไม่ได้ตรวจสอบ)

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
คำตอบที่ดีที่สุดน่าจะเป็นเพียงข้อเดียวที่ป้องกัน "ข้อผิดพลาดการละเมิดวิธีการเปรียบเทียบ" หากการแก้ไขครั้งล่าสุดแก้ไขขณะเรียงลำดับ?
icyerasor

1
สิ่งนี้ควรใช้เมื่อคุณกังวลว่าจะไม่ได้รับ IllegalArgumentException เนื่องจากการเปรียบเทียบวิธีการละเมิด วิธีการใช้แผนที่จะล้มเหลวหากมีมากกว่าหนึ่งไฟล์ที่มีค่า LastModified เดียวกันซึ่งจะส่งผลให้ละเว้นไฟล์เหล่านี้ นี่เป็นคำตอบที่ได้รับการยอมรับอย่างแน่นอน
นักพัฒนา 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 จำเป็นต้องได้รับรายการที่ไม่แน่นอนซึ่งสามารถจัดเรียง) ฉันพบหัวข้อนี้มองหาวิธีการเรียงลำดับรายการไฟล์ ดังนั้นฉันเพิ่งเพิ่มรหัสนั้นเพื่อให้ผู้คนสามารถคัดลอกได้ถ้าพวกเขามีรายการเช่นกัน
starbroken

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 ()) .To เปรียบเทียบ (f2.lastModified ()); แทน api ที่ต่ำกว่า
Martin Sykes

25

คุณอาจจะดูapache คอมมอนส์ IOมันมีตัวเปรียบเทียบที่แก้ไขล่าสุดและยูทิลิตี้ดีๆอื่น ๆ อีกมากมายสำหรับการทำงานกับไฟล์


5
มีข้อผิดพลาดแปลก ๆ ใน javadoc ด้วยวิธีนี้เพราะ javadoc บอกว่าจะใช้ "LastModifiedFileComparator.LASTMODIFIED_COMPARATOR.sort (รายการ);" เพื่อเรียงลำดับรายการ แต่ LASTMODIFIED_COMPARATOR ถูกประกาศเป็น "Comparator <File>" ดังนั้นจึงไม่เปิดเผยวิธี "เรียงลำดับ" ใด ๆ
อุโมงค์

4
ใช้อย่างนี้: link
cleroo

1
File.lastModified อาจเปลี่ยนแปลงในขณะที่การเรียงลำดับผลลัพธ์สุดท้ายในข้อผิดพลาดการละเมิดวิธีการเปรียบเทียบดู: stackoverflow.com/questions/20431031ดูstackoverflow.com/a/4248059/314089เพื่อหาทางออกที่ดีกว่า
icyerasor

1
คอมมอนส์รักที่ช่วยประหยัดเวลาได้มาก
redDevil


13

การนำเข้า:

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

รหัส:

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 คอมมอนส์ ioจะช่วย
บรอดแบนด์

เสร็จแล้วขอบคุณบรอดแบนด์
Balaji Boggaram Ramanarayan

10

หากไฟล์ที่คุณเรียงลำดับสามารถแก้ไขหรืออัพเดตได้ในเวลาเดียวกันการเรียงลำดับจะถูกดำเนินการ:


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


โซลูชันทั้งสองนี้สร้างโครงสร้างข้อมูลแผนที่ชั่วคราวเพื่อประหยัดเวลาแก้ไขล่าสุดสำหรับแต่ละไฟล์ในไดเรกทอรี เหตุผลที่เราต้องทำคือถ้าไฟล์ของคุณมีการปรับปรุงหรือแก้ไขในขณะที่การเรียงลำดับของคุณกำลังดำเนินการแล้วตัวเปรียบเทียบของคุณจะละเมิดข้อกำหนดความไวของสัญญาทั่วไปของอินเทอร์เฟซของ Comparator เพราะเวลาที่แก้ไขล่าสุดอาจเปลี่ยนแปลงในระหว่างการเปรียบเทียบ

หากในอีกทางหนึ่งคุณรู้ว่าไฟล์จะไม่ได้รับการปรับปรุงหรือแก้ไขในระหว่างการเรียงลำดับคุณสามารถหนีไปพร้อมกับคำตอบอื่น ๆ ที่ส่งไปยังคำถามนี้ซึ่งเป็นส่วนหนึ่งของ:

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 ในการดำเนินการสตรีมที่เรียงลำดับอย่างไรก็ตามคุณต้องจัดการกับข้อยกเว้น IO ที่เลือกไว้ภายในแลมบ์ดาของคุณ . ฉันจะบอกว่าถ้าประสิทธิภาพมีความสำคัญมากพอที่การแปลนั้นจะไม่เป็นที่ยอมรับฉันก็จะจัดการกับ IOException ที่ถูกตรวจสอบในแลมบ์ดาโดยการเผยแพร่มันเป็น UncheckedIOException หรือฉันต้องการนำไฟล์ API ทั้งหมดมารวมกัน

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
สิ่งนี้ไม่ได้จัดเรียงในวันที่แก้ไขคุณสมบัติที่กล่าวถึงในคำถาม ฟังก์ชั่นการจัดเรียงจะใช้การสั่งซื้อตามธรรมชาติของวัตถุแฟ้มซึ่งเป็นพจนานุกรมระบบขึ้นอยู่กับชื่อเส้นทาง
Matt Chan

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

โดยที่listFilesเป็นชุดของไฟล์ทั้งหมดใน ArrayList



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

ในส่วน initialisation ของforวงที่คุณสามารถดูฉันได้ถ่ายlist.length-1ไม่เกินi >=0ซึ่งก็ย้ำคุณเพื่อย้อนกลับ
Hirdesh Vishwdewa

0

มีวิธีที่ง่ายและสะดวกในการจัดการปัญหาโดยไม่มีการเปรียบเทียบเพิ่มเติม เพียงพิมพ์รหัสวันที่แก้ไขลงใน String ด้วยชื่อไฟล์จัดเรียงแล้วถอดออกในภายหลัง

ใช้สตริงที่มีความยาวคงที่ 20 ใส่วันที่แก้ไข (ยาว) ลงไปแล้วเติมด้วยศูนย์นำหน้า จากนั้นก็ต่อท้ายชื่อไฟล์ต่อท้ายสตริงนี้:

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

จากนั้นคุณสามารถเรียงลำดับรายการนี้

สิ่งที่คุณต้องทำคือตัด 20 ตัวอักษรอีกครั้งในภายหลัง (ใน Java 8 คุณสามารถตัดมันสำหรับ Array ทั้งหมดด้วยเพียงหนึ่งบรรทัดโดยใช้ฟังก์ชัน. แทนที่ทั้งหมด)


-1

นอกจากนี้ยังมีวิธีที่แตกต่างอย่างสิ้นเชิงซึ่งอาจจะง่ายกว่านี้เพราะเราไม่ได้จัดการกับคนจำนวนมาก

แทนที่จะเรียงลำดับอาร์เรย์ทั้งหมดหลังจากที่คุณเรียกคืนชื่อไฟล์ทั้งหมดและวันที่แก้ไขล่าสุดคุณสามารถแทรกชื่อไฟล์เดียวได้ทุกครั้งหลังจากที่คุณเรียกคืนมาที่ตำแหน่งด้านขวาของรายการ

คุณสามารถทำได้เช่นนี้:

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.