1

の形式でタブ区切りのテキストデータの大規模なコレクションがありますDATE NAME MESSAGE。つまり、1.76GBのコレクションを1075個の実際のファイルに分割したということです。すべてのファイルNAMEからデータを取得する必要があります。今まで私はこれを持っています:

   File f = new File(directory);
        File files[] = f.listFiles();
        // HashSet<String> all = new HashSet<String>();
        ArrayList<String> userCount = new ArrayList<String>();
        for (File file : files) {
            if (file.getName().endsWith(".txt")) {
                System.out.println(file.getName());
                BufferedReader in;
                try {
                    in = new BufferedReader(new FileReader(file));
                    String str;
                    while ((str = in.readLine()) != null) {
                        // if (all.add(str)) {
                        userCount.add(str.split("\t")[1]);
                        // }

                        // if (all.size() > 500)
                        // all.clear();
                    }
                    in.close();
                } catch (IOException e) {
                    System.err.println("Something went wrong: "
                            + e.getMessage());
                }

            }
        }

私のプログラムは、-Xmx1700を使用しても、常にメモリ不足の例外を出します。それを超えることはできません。とにかく、コードを最適化してのを処理できるようにすることはできArrayList<String>ますNAMEか?

4

3 に答える 3

3

Java以外のソリューションを許可しているように見えるので、これを処理する必要があるawkソリューションを次に示します。

cat *.txt | awk -F'\t' '{sum[$2] += 1} END {for (name in sum) print name "," sum[name]}'

説明:

-F'\t' - separate on tabs
sum[$2] += 1 - increment the value for the second element (name)

連想配列はこれを非常に簡潔にします。次のように作成したテストファイルで実行します。

import random

def main():
    names = ['Nick', 'Frances', 'Carl']
    for i in range(10000):
        date = '2012-03-24'
        name = random.choice(names)
        message = 'asdf'
        print '%s\t%s\t%s' %(date, name, message)

if __name__ == '__main__':
    main()

結果が得られます:

Carl,3388
Frances,3277
Nick,3335
于 2012-04-28T02:48:26.767 に答える
1

コードのメモリフットプリントと一般的なパフォーマンスを改善するためにできることがいくつかあります。

  1. 次のオブジェクトに移動する前に、FileReaderオブジェクトを閉じてください。 FileReaderはInputStreamReaderであり、close()リソースを解放するために呼び出す必要があります。現在のコードは、見ているすべてのファイルに対してストリームを効果的に開いたままにしています。

    for( File file: files ) {
        BufferedReader in = null;
        try{
            in = new BufferedReader( new FileReader( file ) );
            // TODO do whatever you want here.
        }
        finally{
            if( in != null ) {
                in.close();
            }
        }
    }
    
  2. 可能であれば、すべてのNAME値をuserCountArrayListに格納しないようにします。ARSが提案したように、最初にこの情報を別のファイルに書き込んでから、そのデータを再度プルする必要があるときにファイルを読み取ることができます。それが魅力的なオプションではない場合でも、情報をOutputStreamに書き込み、それをアプリの他の場所のInputStreamにパイプすることができます。これによりデータがメモリに保持されますが、値のリストを使用している場合は、これらの1,000以上のファイルを読み続けてさらに値NAMEを検索すると、処理/表示などを同時に開始できます。NAME

  3. listFiles(FileFilter)メソッドを使用して、Javaが非テキストファイルを除外できるようにします。これにより、拡張子が正しくないファイルを削除する前に繰り返し処理する必要がなくなるため、CPUサイクルが数回余分に発生するのを防ぐことができます。
于 2012-04-28T02:42:28.590 に答える
1

String.splitは、元の文字列と同じ文字配列を内部的に使用する文字列を返します。未使用の文字はガベージコレクションされません。

new String(str.split( "\ t")[1])を使用して、新しい配列の割り当てを強制してみてください。

于 2012-04-28T02:45:44.973 に答える