2013-01-17 56 views
4

我有一個文件列表,我想排序並提取前3個最後修改。找到文件的長列表中的3個最近修改的文件

約束:我不能對下游應用

我目前的選擇

解決方案使用Java 7由於兼容性問題1

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

解決方案2

public static void sortFilesDesc(File[] files) { 
    Arrays.sort(files, new Comparator() { 
    public int compare(Object o1, Object o2) { 
     if ((File)o1).lastModified().compareTo((File)o2).lastModified()) { 
     return -1; 
     } else if (((File) o1).lastModified() < ((File) o2).lastModified()) { 
     return +1; 
     } else { 
     return 0; 
     } 
    } 
    }); 
} 

問題

上述兩種解決方案需要更多時間來執行內存。我的文件列表包含大約300個每個大小爲200MB的tar文件。所以它消耗更多的時間內存。

有什麼辦法可以有效地處理這個問題嗎?

每個比較操作使用的是高內存的文件對象是否有任何方式來釋放內存並對其進行有效處理?

+0

我認爲你的記憶和時間問題並不是由於你對300個物品的排序(無論如何都在記憶中)。也許你不止一次地進行這種表演? – Howard

+0

不,我正在使用上述兩種解決方案中的任何一種。 「反正在記憶中」你的意思是什麼?我如何清除一旦操作完成。 – Wills

+3

「文件」對象不是一個昂貴的對象!它只包含文件名,而不包含文件的內容。所以文件大小完全不相關。 –

回答

3

你可以做得更快。

Arrays.sort(...)使用「快速排序」,這需要執行〜n * ln(n)操作。

本示例僅通過整個數組執行一次迭代,即〜n操作。

public static void sortFilesDesc(File[] files) {   
    File firstMostRecent = null; 
    File secondMostRecent = null; 
    File thirdMostRecent = null; 
    for (File file : files) { 
     if ((firstMostRecent == null) 
       || (firstMostRecent.lastModified() < file.lastModified())) { 
      thirdMostRecent = secondMostRecent; 
      secondMostRecent = firstMostRecent;    
      firstMostRecent = file; 
     } else if ((secondMostRecent == null) 
       || (secondMostRecent.lastModified() < file.lastModified())) { 
      thirdMostRecent = secondMostRecent; 
      secondMostRecent = file; 
     } else if ((thirdMostRecent == null) 
       || (thirdMostRecent.lastModified() < file.lastModified())) { 
      thirdMostRecent = file; 
     } 
    } 
} 

上的文件數量較少,你不會看到太大的區別,但即使是幾十文件的差別會顯著,更大的數字 - 戲劇性。

檢查算法(請放置於正確的文件結構)的代碼:

package com.hk.basicjava.clasload.tests2; 

import java.io.File; 
import java.util.Date; 


class MyFile extends File { 

    private long time = 0; 

    public MyFile(String name, long timeMills) { 
     super(name); 
     time = timeMills; 
    } 
    @Override 
    public long lastModified() { 
     return time; 
    } 
} 

public class Files { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 

     File[] files = new File[5]; 
     files[0] = new MyFile("File1", new Date(2013,1,15, 7,0).getTime()); 
     files[1] = new MyFile("File2", new Date(2013,1,15, 7,40).getTime()); 
     files[2] = new MyFile("File3", new Date(2013,1,15, 5,0).getTime()); 
     files[3] = new MyFile("File4", new Date(2013,1,15, 10,0).getTime()); 
     files[4] = new MyFile("File5", new Date(2013,1,15, 4,0).getTime()); 
     sortFilesDesc(files); 
    } 

    public static void sortFilesDesc(File[] files) {   
     File firstMostRecent = null; 
     File secondMostRecent = null; 
     File thirdMostRecent = null; 
     for (File file : files) { 
      if ((firstMostRecent == null) 
        || (firstMostRecent.lastModified() < file.lastModified())) { 
       thirdMostRecent = secondMostRecent; 
       secondMostRecent = firstMostRecent;    
       firstMostRecent = file; 
      } else if ((secondMostRecent == null) 
        || (secondMostRecent.lastModified() < file.lastModified())) { 
       thirdMostRecent = secondMostRecent; 
       secondMostRecent = file; 
      } else if ((thirdMostRecent == null) 
        || (thirdMostRecent.lastModified() < file.lastModified())) { 
       thirdMostRecent = file; 
      } 
     } 
     System.out.println("firstMostRecent : " + firstMostRecent.getName()); 
     System.out.println("secondMostRecent : " + secondMostRecent.getName()); 
     System.out.println("thirdMostRecent : " + thirdMostRecent.getName()); 
    } 

} 
+0

請刪除「近6倍」的說法。通過在複雜性公式中插入數字,您可能無法比較不同算法的運行時間。結論是正確的 - 但是論點是有缺陷的。 – Howard

+0

我同意,這並不完全正確;這只是爲了讓人們「感受到不同」。 –

+0

謝謝@AlexKreutznaer。您的解決方案不適用於所有情況下的情況,例如考慮以下內容並針對您的算法進行追蹤。文件名:FXXXXXXXXX改良07:00 HRS 文件名:FXXXXXXXXX改良07:40 HRS 文件名:MXXXXXXXXX改良05:00 HRS 文件名:YXXXXXXXXX改良10:00 <\code> 文件名:YXXXXXXXXX修改04:00 HRS – Wills

3

你必須檢查每個文件的lastmodified,你不能改變它。你並不需要做的是所有元素進行排序只是爲了獲得前3名。如果你可以使用番石榴,您可以使用Ordering.greatestOf(使用一個好的算法):

Ordering<File> ordering = Ordering.from(new Comparator(){ 
     public int compare(File f1, File f2) 
     { 
      return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); 
     }); 

List<File> max3 = ordering.greatestOf(Arrays.asList(directory.listFiles()), 3); 
0

我的解決方案1,有一些改進

Arrays.sort(files, new Comparator<File>() { 
     public int compare(File f1, File f2) { 
      long d1 = f1.lastModified(); 
      long d2 = f2.lastModified(); 
      return d1 > d2 ? 1 : d1 < d2 ? -1 : 0; 
     } 
    }); 

避免由於Long.valueOf(long)而導致不必要的對象創建。

File不保存/讀取任何文件數據,但只有文件路徑,它沒有性能/內存問題。這裏唯一耗時的操作是從文件系統讀取無法避免的修改時間。

+0

Long.compare出現在Java 7中,並且問題提出了非Java 7解決方案。 –

+0

現在,您已將代碼更改爲無法編譯的代碼(不兼容類型,int/long)。 –

+0

與原始代碼相比,這是爲什麼改進? –

0

你的問題是,獲取最後的修改日期是一個相對昂貴的操作,因爲它涉及到操作系統的邏輯。因此,如果您不介意獲取最新的最新值,則可以將文件包裝到可比較的類中。

public class LastModifiedFile implements Comparable<LastModifiedFile> { 

    private final File file; 
    private final Date lastModified; 

    public LastModifiedFile(File file) { 
     this.file = file; 
     lastModified = file.lastModified(); 
    } 

    public int compareTo(LastModifiedFile other) { 
     return lastModified.compareTo(other.lastModified); 
    } 
} 

請注意,在排序過程中更改最後修改日期會導致許多排序算法的未定義行爲。 Java 7s Tim Sort的實現會拋出一個異常,如果最後一次修改日期發生變化,因此比較會導致不同的值。

相關問題