2009-10-16 16 views
7

ecco un'altra domanda su splice(). Spero di usarlo per copiare i file, e sto cercando di usare due chiamate di giunzione unite da una pipe come nell'esempio sulla pagina Wikipedia di splice. Ho scritto un semplice banco di prova, che cerca solo di leggere i primi 32K byte da un file e scrivere ad un altra:Come posso usare la funzione splice() di Linux per copiare un file in un altro file?

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

Quando eseguo questo, il file di input sembra essere letto correttamente, ma la seconda chiamata giunzione fallisce con EINVAL. Qualcuno sa cosa sto facendo male qui?

Grazie!

+0

Per chiunque stia leggendo questo, la seconda chiamata 'splice' dovrebbe provare a leggere il numero di byte dalla pipe come la prima chiamata' splice' restituita. Su Linux di oggi, la dimensione del pipe di default è '65535'. – Jite

risposta

3

Che tipo di file system si sta copiando da/per?

L'esempio viene eseguito sul mio sistema quando entrambi i file si trovano su ext3 ma non riescono quando utilizzo un'unità esterna (ho dimenticato la mano se è DOS o NTFS). La mia ipotesi è che uno o entrambi i file siano su un file system che la giunzione non supporta.

+0

NTFS avrebbe senso - questo è implementato tramite FUSE e il driver del filesystem reale viene eseguito come un processo userspace. Con altri filesystem, otoh, il filesystem può sfogliare direttamente con la cache della pagina. È un vero peccato che splice() 'non abbia un fallback automatico pulito in un ciclo di copia però ... – bdonlan

+0

È NTFS anche se non sembra che splice funzioni su DOS. Accetto il fallback. Sono tentato di fare alcuni semplici benchmark in quanto sembra impressionante a occhio nudo. – Duck

4

Dal 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. 

Sappiamo uno dei descrittori è un tubo, e il file non è aperto in modalità di accodamento. Sappiamo anche che non viene fornito alcun offset (0 equivale a NULL - intendevi passare un puntatore a un offset zero?), Quindi non è questo il problema. Pertanto, il filesystem che stai utilizzando non supporta lo splicing sui file.

+0

Questo era il problema. Grazie! Avrei dovuto leggere la pagina man fino in fondo e non mi ero reso conto che la giunzione dipendesse dal filesystem. Nel mio caso stavo copiando su un filer NFS. Sto cercando di trovare il modo più veloce per copiare molti file (che mediamente a circa 10 MB) da un file system NFS a un altro. mmapizzare il file sorgente e usare write() non stanno ottenendo risultati spettacolari. Grazie per i suggerimenti! –

2

Il splice(2) system call è per copiare tra file e pipe e non tra file, quindi non può essere utilizzato per copiare tra file, come è stato sottolineato dalle altre risposte.

A partire da Linux 4.5 è tuttavia disponibile un nuovo copy_file_range(2) system call in grado di copiare i file. Nel caso di NFS può anche causare la copia sul lato server.

La pagina man collegata contiene un programma di esempio completo.

Problemi correlati