C
C++
ファイル操作
fstream
速度

C/C++のファイル操作速度比較

More than 1 year has passed since last update.

C++は最速!!と思い込んでいました。ネットで「Cのべた書きとSTLはどっちが速い」なんて、C++速いぞって記事をたまに見かけるでしょう。
しかし実際にfstreamを使ったファイルコピーを書いてみたら、C++、意外に遅いか?という結果に・・・。具体的にどれぐらい違うのかC標準ライブラリとの実行速度の比較を行なってみました。

環境

使用したのはVisualStudio 2008。VS2013でもあまり変わらないみたいです。

コード

比較したコードは下記の4つ。いづれも入力ファイルから出力ファイルへバイナリコピーします。エラー処理は省いています。

1:streambuf_iteratorとcopy()を使う

C++
void CopyFile( const char *from_file_name, const char *to_file_name )
{
    ifstream is( from_file_name, ios::in | ios::binary );
    ofstream os( to_file_name, ios::out | ios::binary );

    // ファイルコピー
    istreambuf_iterator<char> iit(is);
    istreambuf_iterator<char> end;
    ostreambuf_iterator<char> oit(os);
    copy( iit, end, oit );
}

2:fstream::rdbuf()と<<を使う

C++
void CopyFile( const char *from_file_name, const char *to_file_name )
{
    ifstream is( from_file_name, ios::in | ios::binary );
    ofstream os( to_file_name, ios::out | ios::binary );

    // ファイルコピー
    os << is.rdbuf();
}

3:fstreamとバッファ(1MB)を使う

c++
void CopyFile( const char *from_file_name, const char *to_file_name )
{
    ifstream is( from_file_name, ios::in | ios::binary );
    ofstream os( to_file_name, ios::out | ios::binary );

    // バッファ確保
    vector<char> buffer( 1024*1024 );
    // ファイルコピー
    while( !is.eof() )
    {
        size_t size = is.read( &buffer[0], buffer.size() ).gcount();
        os.write( &buffer[0], size );
    }
}

4:Cの標準ライブラリとバッファ(1MB)を使う

C++
void CopyFile( const char *from_file_name, const char *to_file_name )
{
    FILE *fpr = fopen( from_file_name, "rb" );
    FILE *fpw = fopen( to_file_name , "wb" );

    // バッファ確保
    vector<char> buffer( 1024*1024 );
    // ファイルコピー
    while( !feof( fpr ) )
    {
        size_t size = fread( &buffer[0], 1, buffer.size(), fpr );
        fwrite( &buffer[0], 1, size, fpw );
    }
    fclose( fpr );
    fclose( fpw );
}

結果

Cの標準ライブラリが数倍速いです。

コード 処理時間・キャッシュなし (ms) 処理時間・キャッシュあり(ms)
1:streambuf_iteratorとcopy() 2,400 2.000
2:fstream::rdbuf()と<< 2,000 1,900
3:fstreamとバッファ 1,200 500
4:Cの標準ライブラリ 650 90

「キャッシュなし」はファイルのメモリへの初回読み込み、「キャッシュあり」は2回目以降の読み込みです。「キャッシュあり」はあまり意味がないと思ったのですが、速度差が大きいので載っけておきました。

キャッシュなしで比較すると、1or2(fstream+algorithm)と3(fstream)の速度比がおおざっぱに2倍、3(fstream)と4(Cライブラリ)の速度比も2倍ですから、fstream遅いわ、copy(),<<等のアルゴリズム遅いわで、両者の共犯でこの速度差になっていると推測できます。

(測定条件)130Mバイトのファイルを使用。x86。普通のリリースモード(速度最適化)。処理時間は多少ばらつくので数回実行して目分量で丸めています。

まとめ

CとC++(fstream)で数倍の差が出たのはちょっと驚きでした。
速度を求めるときfstreamは使用できませんね。

番外:C#

C#でも同様のコードを書いて試してみました。

C#
private static void CopyFile( string from, string to )
{
    using( BinaryReader br = new BinaryReader( File.OpenRead( from ) ) )
    using( BinaryWriter bw = new BinaryWriter( File.OpenWrite( to ) ) ) 
    {
        // ファイルコピー
        while(true)
        {
            byte[] buf = br.ReadBytes( 1024*1024 );
            if( buf.Length == 0 )
                break;
            bw.Write( buf );
        }
    }
}
コード 処理時間・キャッシュなし(ms) 処理時間・キャッシュあり(ms)
C# 650 130

速い。Cライブラリに肉薄。