Как я могу использовать функцию splice() Linux для копирования файла в другой файл?
вот еще один вопрос о Splice(). Я надеюсь использовать его для копирования файлов и пытаюсь использовать два вызова 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("%dn", result);
result = splice(pipefd[0], NULL, fileno(out_file), 0, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
printf("%dn", result);
if (result == -1)
printf("%d - %sn", errno, strerror(errno));
close(pipefd[0]);
close(pipefd[1]);
fclose(in_file);
fclose(out_file);
return 0;
}
когда я запускаю это, входной файл, кажется, читается правильно, но второй вызов соединения терпит неудачу с EINVAL. Кто-нибудь знает что я делаю неправильно здесь?
спасибо!
3 ответов
какую файловую систему(ы) копирование в/из?
ваш пример работает в моей системе, когда оба файла находятся на ext3, но терпит неудачу, когда я использую внешний диск (я забываю, что это DOS или NTFS). Я предполагаю, что один или оба ваших файла находятся в файловой системе, которую splice не поддерживает.
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
- вы хотели передать указатель на нулевое смещение?), так что проблема не в этом. Поэтому используемая файловая система не поддерживает сращивание с файлами.
на splice(2)
системный вызов предназначен для копирования между файлами и трубами, а не между файлами, поэтому его нельзя использовать для копирования между файлами, как было указано в других ответах.
С Linux 4.5 однако новый copy_file_range(2)
системный вызов доступно, что может копировать между файлами. В случае NFS это может даже вызвать копирование на стороне сервера.
связанная man-страница содержит полный пример программы.