Как я могу использовать функцию 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 не поддерживает.


С сплайс 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.

мы знаем, что один из дескрипторов является каналом, и файл не открыт в режиме добавления. Мы также знаем, что смещение не задано (0 эквивалентно NULL - вы хотели передать указатель на нулевое смещение?), так что проблема не в этом. Поэтому используемая файловая система не поддерживает сращивание с файлами.


на splice(2) системный вызов предназначен для копирования между файлами и трубами, а не между файлами, поэтому его нельзя использовать для копирования между файлами, как было указано в других ответах.

С Linux 4.5 однако новый copy_file_range(2) системный вызов доступно, что может копировать между файлами. В случае NFS это может даже вызвать копирование на стороне сервера.

связанная man-страница содержит полный пример программы.