7

这是关于 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;
}

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

谢谢!

4

3 回答 3

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.

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

于 2009-10-17T01:10:22.080 回答
3

您要复制到/从哪种文件系统?

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

于 2009-10-17T01:33:28.733 回答
2

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

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

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

于 2016-08-09T02:37:21.320 回答