如何使用Linux的splice()函数将文件复制到另一个文件?

时间:2022-12-15 21:27:05

here's another question about splice(). I'm hoping to use it to copy files, and am trying to use two splice calls joined by a pipe like the example on splice's Wikipedia page. I wrote a simple test case which only tries to read the first 32K bytes from one file and write them to another:

这是关于splice()的另一个问题。我希望用它来复制文件,并且我试图使用两个splice调用连接管道,就像splice的Wikipedia页面上的例子一样。我写了一个简单的测试用例,它只试图从一个文件读取前32K字节并将它们写入另一个文件:

#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;
}

When I run this, the input file seems to be read properly, but the second splice call fails with EINVAL. Anybody know what I'm doing wrong here?

当我运行它时,输入文件似乎正确读取,但第二次拼接调用失败了EINVAL。谁知道我在这里做错了什么?

Thanks!

3 个解决方案

#1


3  

What kind of file system(s) are you copying to/from?

你要复制什么样的文件系统?

Your example runs on my system when both files are on ext3 but fails when I use an external drive (I forget offhand if it is DOS or NTFS). My guess is that one or both of your files are on a file system that splice does not support.

当两个文件都在ext3上时你的例子在我的系统上运行但在我使用外部驱动器时失败(如果它是DOS或NTFS我会忘记)。我的猜测是你的一个或两个文件都在splice不支持的文件系统上。

#2


4  

From the splice manpage:

从拼接手册页:

   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.

We know one of the descriptors is a pipe, and the file's not open in append mode. We also know no offset is given (0 is equivalent to NULL - did you mean to pass in a pointer to a zero offset?), so that's not the problem. Therefore, the filesystem you're using doesn't support splicing to files.

我们知道其中一个描述符是一个管道,并且该文件未在追加模式下打开。我们也知道没有给出偏移量(0相当于NULL - 你的意思是传入指向零偏移的指针吗?),所以这不是问题。因此,您使用的文件系统不支持拼接文件。

#3


2  

The splice(2) system call is for copying between files and pipes and not between files, so it can not be used to copy between files, as has been pointed out by the other answers.

splice(2)系统调用用于文件和管道之间的复制,而不是文件之间的复制,因此不能用于在文件之间进行复制,正如其他答案所指出的那样。

As of Linux 4.5 however a new copy_file_range(2) system call is available that can copy between files. In the case of NFS it can even cause server side copying.

从Linux 4.5开始,可以使用新的copy_file_range(2)系统调用来复制文件。在NFS的情况下,它甚至可以导致服务器端复制。

The linked man page contains a full example program.

链接的手册页包含完整的示例程序。

#1


3  

What kind of file system(s) are you copying to/from?

你要复制什么样的文件系统?

Your example runs on my system when both files are on ext3 but fails when I use an external drive (I forget offhand if it is DOS or NTFS). My guess is that one or both of your files are on a file system that splice does not support.

当两个文件都在ext3上时你的例子在我的系统上运行但在我使用外部驱动器时失败(如果它是DOS或NTFS我会忘记)。我的猜测是你的一个或两个文件都在splice不支持的文件系统上。

#2


4  

From the splice manpage:

从拼接手册页:

   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.

We know one of the descriptors is a pipe, and the file's not open in append mode. We also know no offset is given (0 is equivalent to NULL - did you mean to pass in a pointer to a zero offset?), so that's not the problem. Therefore, the filesystem you're using doesn't support splicing to files.

我们知道其中一个描述符是一个管道,并且该文件未在追加模式下打开。我们也知道没有给出偏移量(0相当于NULL - 你的意思是传入指向零偏移的指针吗?),所以这不是问题。因此,您使用的文件系统不支持拼接文件。

#3


2  

The splice(2) system call is for copying between files and pipes and not between files, so it can not be used to copy between files, as has been pointed out by the other answers.

splice(2)系统调用用于文件和管道之间的复制,而不是文件之间的复制,因此不能用于在文件之间进行复制,正如其他答案所指出的那样。

As of Linux 4.5 however a new copy_file_range(2) system call is available that can copy between files. In the case of NFS it can even cause server side copying.

从Linux 4.5开始,可以使用新的copy_file_range(2)系统调用来复制文件。在NFS的情况下,它甚至可以导致服务器端复制。

The linked man page contains a full example program.

链接的手册页包含完整的示例程序。