5

最後に変更された上位3つを並べ替えて抽出したいファイルリストがあります。

制約:ダウンストリームアプリの互換性の問題により、Java7を使用できません

私の現在のオプション

解決策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;
      }
    }
  });
}

問題

上記の2つのソリューションは、実行とメモリに時間がかかります。私のファイルリストは、それぞれ200MBのサイズの約300のtarファイルで構成されています。そのため、より多くの時間とメモリを消費します。

これを効率的に処理する方法はありますか?

すべての比較操作でメモリの多いファイルオブジェクトが使用されますが、メモリを解放してこれを効果的に処理する方法はありますか?

4

4 に答える 4

5

あなたはそれをはるかに速くすることができます。

Arrays.sort(...)は、〜n * ln(n)操作を行う「クイックソート」を使用します。

この例では、配列全体で1回の反復のみを行います。これは、〜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());
    } 

}
于 2013-01-17T06:11:27.860 に答える
3

すべてのファイルのlastModifiedを確認する必要があり、変更することはできません。あなたがする必要がないのは、トップ3を取得するためだけにすべての要素をソートすることです。Guavaを使用できる場合は、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);
于 2013-01-17T05:47:47.603 に答える
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);
    }
}

並べ替え中に最終変更日を変更すると、多くの並べ替えアルゴリズムで未定義の動作が発生することに注意してください。最終変更日が変更されたために比較の結果が異なる場合、Java7sのTimSort実装は例外をスローします。

于 2013-01-17T08:51:35.913 に答える
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ファイルデータを保持/読み取りせず、ファイルパスのみを保持し、パフォーマンス/メモリの問題はありません。ここでの唯一の時間のかかる操作は、ファイルシステムから変更時間を読み取ることです。これは避けられません。

于 2013-01-17T05:50:47.097 に答える