2009-10-16 5 views
7

splice()に関するもう1つの質問です。私はファイルをコピーするためにそれを使用することを望んでおり、spliceのWikipediaページの例のようなパイプで結合された2つのスプライス呼び出しを使用しようとしています。私はこれを実行すると、入力ファイルを正しく読み取ることのようですLinuxのsplice()関数を使用してファイルを別のファイルにコピーするにはどうすればよいですか?

#define _GNU_SOURCE 
#include <fcntl.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

int main(int argc, char **argv) { 
    int pipefd[2]; 
    int result; 
    FILE *in_file; 
    FILE *out_file; 

    result = pipe(pipefd); 

    in_file = fopen(argv[1], "rb"); 
    out_file = fopen(argv[2], "wb"); 

    result = splice(fileno(in_file), 0, pipefd[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE); 
    printf("%d\n", result); 

    result = splice(pipefd[0], NULL, fileno(out_file), 0, 32768, SPLICE_F_MORE | SPLICE_F_MOVE); 
    printf("%d\n", result); 

    if (result == -1) 
     printf("%d - %s\n", errno, strerror(errno)); 

    close(pipefd[0]); 
    close(pipefd[1]); 
    fclose(in_file); 
    fclose(out_file); 

    return 0; 
} 

が、2番目のスプライスコール:私は別のものにそれらを一つのファイルから最初の32Kバイトを読み書きしようとすると、簡単なテストケースを書きましたEINVALで失敗します。誰も私がここで間違っていることを知っていますか?

ありがとうございます! splice manpageから

+0

これを読んだ人には、2番目の 'splice'呼び出しは、返された最初の' splice'呼び出しのように、パイプからのバイト数を読み取ろうとするべきです。今日のLinuxでは、デフォルトのパイプサイズは「65535」です。 – Jite

答えて

3

どのファイルシステムをコピーしていますか?

あなたの例は、両方のファイルがext3上にあるときに私のシステム上で動作しますが、外付けドライブを使用すると失敗します(DOSまたはNTFSの場合は忘れてしまいます)。私の推測では、スプライスがサポートしていないファイルシステム上に、あなたのファイルの一方または両方があるということです。

+0

NTFSは理にかなっています。これはFUSE経由で実装されており、実際のファイルシステムドライバはユーザー空間プロセスとして実行されます。他のファイルシステムotohでは、ファイルシステムはページキャッシュを使って直接アクセスできます。 Splice()はコピーループにクリーンな自動フォールバックを持っていません... – bdonlan

+0

スプライスはDOSでも動作しないようですが、NTFSです。フォールバックについて同意する。私は肉眼検査で印象的なように簡単なベンチマークをしたいと思っています。 – Duck

4

EINVAL Target file system doesn't support splicing; target file is 
      opened in append mode; neither of the descriptors refers to a 
      pipe; or offset given for non-seekable device. 

私たちは、記述子のいずれかがパイプである知っている、そしてファイルを追加モードで開かれていないのです。オフセットが与えられていないこともわかっています(0NULLに相当します - ゼロオフセットへのポインタを渡すことを意味しましたか?)、それは問題ではありません。したがって、使用しているファイルシステムはファイルへのスプライシングをサポートしていません。

+0

それは問題でした。ありがとう!私はマニュアルページを一通り読んでいて、スプライスがファイルシステムに依存していることを知らなかった。私の場合は、NFSファイラーにコピーしていました。 私は、1つのNFSファイルシステムから別のファイルシステムに多くのファイル(平均約10MB)をコピーする最速の方法を見つけようとしています。ソースファイルのmmap-ingとwrite()の使用はすばらしく実行されません。 ポインタをありがとう! –

2

splice(2) system callは、ファイルとパイプの間ではなくファイル間でコピーするため、他の回答によって指摘されているようにファイル間のコピーには使用できません。

しかしLinux 4.5では、ファイル間でコピーできる新しいcopy_file_range(2) system callが利用可能です。 NFSの場合、サーバ側のコピーを引き起こす可能性もあります。

リンクされたマニュアルページには、完全なサンプルプログラムが含まれています。

関連する問題