2012-05-10 9 views
1

私のコードでは、あるファイルから別のファイルにデータをコピーする必要がある状況があります。解決策は、私はこのようなルックスを思い付いた:C/C++のあるファイルから別のファイルにデータをコピーする最速の方法は?

const int BUF_SIZE = 1024; 
char buf[BUF_SIZE]; 

int left_to_copy = toCopy; 
while(left_to_copy > BUF_SIZE) 
{ 
    fread(buf, BUF_SIZE, 1, fin); 
    fwrite(buf, BUF_SIZE, 1, fout); 
    left_to_copy -= BUF_SIZE; 
} 

fread(buf, left_to_copy, 1, fin); 
fwrite(buf, left_to_copy, 1, fout); 

私の主な考えはmemcpyのようなものがあるかもしれないということでしたが、ファイル内のデータのために。私はそれに2つのファイルストリームと合計バイト数を与えます。私は少し捜したが、私はそのようなものを見つけることができなかった。

しかし、そのようなものが利用できない場合は、転送を最も速くするためにどのバッファサイズを使用する必要がありますか?システムコールの数が増えれば増えるだろうが、システム上の他のバッファリングやキャッシングを混乱させる可能性があると私は考えた。バッファを動的に割り当てて、読み込み/書き込み呼び出しのペアだけを取る必要がありますか?この場合の典型的な転送サイズは、数KBから数十MB程度です。

EDIT:OS固有の情報については、Linuxを使用しています。

EDIT2:

私はsendfileの使用してみましたが、それはうまくいきませんでした。それは正しい量のデータを書くように思えましたが、それはごみでした。

私はこのようなもので、上記の私の例を置き換える:

fflush(fin); 
fflush(fout); 
off_t offset = ftello64(fin); 
sendfile(fileno(fout), fileno(fin), &offset, toCopy); 
fseeko64(fin, offset, SEEK_SET); 

私はフラッシュ、offest、それが動作するようには見えなかったので、一度に一つを求めてを追加しました。

+6

これを実行する最速の方法は、OSに依存するAPIを使用することになりそうです。 – Lalaland

+4

単純なifstream iの何が問題なのですか? ofstream o;/*両方を開く* /; o << i.rdbuf(); '?保証された移植性は無視するものではありません... – ildjarn

+0

fread()とfwrite()には戻り値があります。それらをチェック/使用する必要があります。 – Ras

答えて

2

ことの一つは、あなたのバッファのサイズを増やしています。大きなファイルがある場合は、それが役に立ちます。

もう1つのことは、あなたのケースにあるかもしれない何でも、OSに直接呼び出すことです。いくつかのオーバーヘッドがありますfread()と​​

バッファリングされていないルーチンを使用し、独自の大きなバッファを提供できる場合は、パフォーマンスが大幅に向上することがあります。

完了したら、戻り値から書き込まれたバイト数をfread()から取得することをおすすめします。

+0

大きなバッファも試してみます。このようにデータをシャベルするための推奨サイズはありますか?また、「戻り値から書き込まれたバイト数」をどのように使用して助けになるかはわかりません。私の場合は、残りの量がバッファのサイズよりも大きい間にループを使用します。もし私がそれにバッファをあふれさせるより大きい数を与えたら。 – stands2reason

+0

バッファーに最適なサイズは、使用可能なメモリー量とコピーされるファイルのサイズによって異なります。あなたはそれで遊ぶ必要があります。私は過去に半分のメグを割り当てました(もちろん、動的に割り当てられました)。コピーするバイト数から 'fread()'によって返された値を単純に減算することができます。さらに簡単に言えば、 'fread()'が 'BUF_SIZE'よりも少ない値を返すまでループすることができます。その場合、ファイルのサイズを決定する必要はありません。それは大きな違いはありませんが、それはちょうど私に奇妙に見えました。 –

+0

OK、プロファイリングを行いました。私は時間のコマンドを使用して、1Kのバッファには1m31、1Mのバッファには59m、動的に割り当てられた12Mのバッファには26sを見つけました。少なくとも、RAMの量に対するバッファサイズがスワッピングが問題にならないようなものであれば、コピーを計画している最大のものが最大のものと同じくらいの大きさのバッファを作成するように見えます。 – stands2reason

9

ご希望のOSを教えてください。適切な呼(または最も適合する呼び出し)は、システム固有のものです。

Linux/* BSD/Macでは、カーネル空間でのコピーを処理するsendfile(2)を使用します。

形式

#include <sys/sendfile.h> 
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); 

DESCRIPTION

sendfile() copies data between one file descriptor and another. Because this 
copying is done within the kernel, sendfile() is more efficient than the 
combination of read(2) and write(2), which would require transferring data to 
and from user space. 

in_fd should be a file descriptor opened for reading and out_fd should be a 
descriptor opened for writing. 

さらにリーディング:

+0

Linuxの場合、これはまさに私が探しているもののようです。私は来週にそれを試して、それがどのように動作するか見ることができます。 – stands2reason

+0

sendfileを試しましたか?読み取り/書き込みループがsendfileと同じくらい速くできる方法は事実上ありません。 Googleの "sendfile"を参照して、sendfileで読み書きループを置き換えるのにどれくらい広く使われているシステムの作業を参照してください... – kay

+0

OK、試しました。私は私の質問に情報を追加しました。 – stands2reason

2

ターゲットオペレーティングシステムのメモリマップファイルI/Oを検討する価値があります。あなたが話しているファイルサイズについては、これは実行可能な方法であり、OSはあなたができるよりも最適化されます。あなたがポータブルOSコードを書こうと思っているなら、これは最善の方法ではないかもしれません。

これはいくつかの設定が必要ですが、一度設定したら、ループコード&は基本的にmemcpyのように見えます。

0

速い読みは私が考える限り、ファイルのマッピングを選択することができます - mmap(mmapのマニュアルページを参照)を使ったメモリマップI/O。特に大きなファイルを処理する場合は、従来のI/Oと比較して効率的であると考えられます。

mmapは実際にファイルを読み取っていません。アドレス空間にマップするだけです。だからこそ速く、アドレス空間のその領域に実際にアクセスするまで、ディスクI/Oはありません。

ブロックサイズを最初に見ることができます。その場合、コンパイラは最適化を強化するため、効率的であると考えられます。

関連する問題