istream -> ostream 時の進捗表示

http://d.hatena.ne.jp/janus_wel/20100618/1276854557 で std::transform() を使って進捗表示をする、とかやってたんだけど fstream やなんかの stream 間の単純な copy なら std::istream::read() と std::ostream::write を使って以下のようにしたほうが速いことに気付いた。

#include <fstream>
#include <iomanip>
#include <iostream>
#include <vector>

int main(void) {
    // build fstream objects fin and fout
    // allocate buffers buf
    // get file size as denominator

    std::cerr << std::fixed << std::setprecision(2);
    std::streamsize numerator = 0;
    double percentage = 0;
    while (fin.good()) {
        fin.read(buf, buf_size);
        fout.write(buf, fin.gcount());
        numerator += fin.gcount();
        percentage = static_cast<double>(numerator) * 100 / denominator;

        std::cerr
            << "\r"
            << numerator << "/" << denominator
            << "(" << percentage << "%)";
    }
}

こっちのがわかりやすいね。速度は buffer の大きさに依存するぽい。今の PC ならけっこう大きめに buffer を取るとけっこう速く処理してくれる ( うちの場合 20MB 弱の file が buffer 1MB で約 2 秒 ) 。まぁ外部から指定できるようにしとけば融通が利くかな。

ちなみに進捗表示がいらないなら以下のように書けばちょっぱやで処理が終わる ( 20MB 弱の file が約 1 秒 ) 。

fout << fin.rdbuf();