这是关于splice()的另一个问题。我希望用它来复制文件,我试图使用两个拼接调用,通过像splice维基百科页面上的例子一样的管道连接。我写了一个简单的测试用例,它只试图从一个文件读取前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而失败。有谁知道我在这里做错了什么?
谢谢!
答案 0 :(得分: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
- 你的意思是传递指向零偏移的指针吗?),所以这不是问题。因此,您使用的文件系统不支持拼接文件。
答案 1 :(得分:3)
您要复制哪种文件系统?
当两个文件都在ext3上时,你的例子在我的系统上运行,但是当我使用外部驱动器时,你的例子会失败(如果它是DOS或NTFS,我会忘记它)。我的猜测是你的一个或两个文件都在splice不支持的文件系统上。
答案 2 :(得分:2)
splice(2)
system call用于文件和管道之间的复制,而不是文件之间的复制,因此不能用于在文件之间进行复制,正如其他答案所指出的那样。
从Linux 4.5开始,可以使用新的copy_file_range(2)
system call来复制文件。对于NFS,它甚至可以导致服务器端复制。
链接的手册页包含完整的示例程序。