1. ホーム

[解決済み】Javaでファイル内の行数について

2022-04-06 02:21:30

質問

私は巨大なデータファイルを使用していますが、時々、これらのファイルの行数を知る必要があります。通常は、ファイルを開いて、ファイルの終わりに達するまで行ごとに読みます。

もっとスマートな方法はないものかと考えていました。

どのように解決するのですか?

これは私がこれまで見つけた中で最速のバージョンで、readLinesの約6倍の速さです。150MBのログファイルでは、readLines()を使った場合の2.40秒に対して、0.35秒で済みます。ちなみに、linuxのwc -lコマンドは0.15秒です。

public static int countLinesOld(String filename) throws IOException {
    InputStream is = new BufferedInputStream(new FileInputStream(filename));
    try {
        byte[] c = new byte[1024];
        int count = 0;
        int readChars = 0;
        boolean empty = true;
        while ((readChars = is.read(c)) != -1) {
            empty = false;
            for (int i = 0; i < readChars; ++i) {
                if (c[i] == '\n') {
                    ++count;
                }
            }
        }
        return (count == 0 && !empty) ? 1 : count;
    } finally {
        is.close();
    }
}

EDIT、9年半後。私は実質的にJavaの経験がないのですが、とにかくこのコードのベンチマークを LineNumberReader というのも、誰もやっていないことが気になったからです。特に大きなファイルに対しては、私のソリューションの方が速いようです。しかし、オプティマイザがまともな仕事をするまで、何回か実行する必要があるようです。私はコードを少し弄って、常に最速となる新しいバージョンを作りました。

public static int countLinesNew(String filename) throws IOException {
    InputStream is = new BufferedInputStream(new FileInputStream(filename));
    try {
        byte[] c = new byte[1024];

        int readChars = is.read(c);
        if (readChars == -1) {
            // bail out if nothing to read
            return 0;
        }

        // make it easy for the optimizer to tune this loop
        int count = 0;
        while (readChars == 1024) {
            for (int i=0; i<1024;) {
                if (c[i++] == '\n') {
                    ++count;
                }
            }
            readChars = is.read(c);
        }

        // count remaining characters
        while (readChars != -1) {
            System.out.println(readChars);
            for (int i=0; i<readChars; ++i) {
                if (c[i] == '\n') {
                    ++count;
                }
            }
            readChars = is.read(c);
        }

        return count == 0 ? 1 : count;
    } finally {
        is.close();
    }
}

1.3GB のテキストファイルのベンチマーク結果、Y 軸は秒。同じファイルを使って100回実行し、それぞれの実行を System.nanoTime() . ご覧の通り countLinesOld にはいくつかの異常値があり countLinesNew がなく、ほんの少し速いだけですが、その差は統計的に有意です。 LineNumberReader は明らかに遅い。