2009-10-16 36 views
7

đây là một câu hỏi khác về mối nối(). Tôi hy vọng sẽ sử dụng nó để sao chép các tập tin, và đang cố gắng sử dụng hai cuộc gọi ghép nối với nhau bằng một đường ống giống như ví dụ trên trang Wikipedia của mối nối. Tôi đã viết một trường hợp thử nghiệm đơn giản mà chỉ cố gắng đọc 32K byte đầu tiên từ một tập tin và viết chúng vào một:Làm cách nào để sử dụng chức năng ghép nối() của Linux để sao chép tệp sang một tệp khác?

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

Khi tôi chạy này, các tập tin đầu vào dường như được đọc đúng, nhưng các cuộc gọi nối thứ hai thất bại với EINVAL. Có ai biết tôi đang làm gì sai ở đây không?

Cảm ơn!

+0

Đối với bất kỳ ai đọc điều này, lệnh gọi 'splice' thứ hai chỉ nên đọc số byte từ đường ống khi lệnh gọi' splice' đầu tiên được trả về. Vào các ngày của Linux, kích thước ống mặc định là '65535'. – Jite

Trả lời

3

Bạn đang sao chép (các) hệ thống tệp nào?

Ví dụ của bạn chạy trên hệ thống của tôi khi cả hai tệp trên ext3 nhưng không thành công khi tôi sử dụng ổ đĩa ngoài (tôi quên tự tay nếu đó là DOS hoặc NTFS). Tôi đoán là một hoặc cả hai tệp của bạn nằm trên hệ thống tệp mà mối nối không hỗ trợ.

+0

NTFS sẽ có ý nghĩa - được thực hiện thông qua FUSE và trình điều khiển hệ thống tệp thực tế chạy dưới dạng quy trình không gian người dùng. Với các hệ thống tập tin khác, otoh, hệ thống tập tin có thể tương thích với bộ đệm trang trực tiếp. Đó là một sự xấu hổ 'splice()' không có một dự phòng tự động sạch sẽ cho một vòng lặp mặc dù ... – bdonlan

+0

Nó là NTFS mặc dù mối nối dường như không hoạt động trên DOS. Đồng ý về dự phòng. Tôi bị cám dỗ để làm một số tiêu chuẩn đơn giản vì nó có vẻ ấn tượng với kiểm tra mắt thường. – Duck

4

Từ 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. 

Chúng tôi biết một trong những mô tả là một đường ống, và các tập tin không mở trong chế độ append. Chúng tôi cũng biết không có bù đắp nào được đưa ra (0 tương đương với NULL - ý của bạn là chuyển một con trỏ tới số không bù trừ?), Vì vậy đó không phải là vấn đề. Do đó, hệ thống tệp bạn đang sử dụng không hỗ trợ ghép nối với tệp.

+0

Đó là vấn đề. Cảm ơn! Tôi nên đã đọc trang người đàn ông tất cả các cách thức thông qua, và không nhận ra rằng mối nối là phụ thuộc vào hệ thống tập tin. Trong trường hợp của tôi, tôi đã sao chép vào một trình ghi NFS. Tôi đang cố tìm cách nhanh nhất để sao chép nhiều tệp (trung bình khoảng 10MB) từ một hệ thống tệp NFS sang hệ thống tệp khác. mmap-ing tập tin nguồn và sử dụng write() không thực hiện ngoạn mục. Cảm ơn các con trỏ! –

2

splice(2) system call là để sao chép giữa các tệp và đường ống chứ không phải giữa các tệp, do đó không thể sử dụng để sao chép giữa các tệp, như đã được các câu trả lời khác chỉ ra.

Kể từ Linux 4.5 tuy nhiên, copy_file_range(2) system call mới khả dụng có thể sao chép giữa các tệp. Trong trường hợp của NFS nó thậm chí có thể gây ra sao chép phía máy chủ.

Trang người được liên kết chứa một chương trình ví dụ đầy đủ.

Các vấn đề liên quan