tee函數

tee函數在兩個管道文件描述符之間複製數據,也是零拷貝操作,它不消耗數據,所以其源文件描述符上的數據仍然可用於後續的讀操作,其函數原型如下:

ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

其參數和上篇splice函數的參數意義相同,但是fd_in和fd_out必須是管道文件描述符,函數成功返回在兩個文件描述符之間複製的數據字節數,返回0沒有複製任何數據,返回-1表示失敗並設置errno。

下例代碼用tee函數實現了linux tee命令的基本功能:

#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#define LEN 654
int main(int argc,char *argv[])
{
    if(argc < 2)
    {
        printf("usage: %s <file>\n",argv[0]);
        exit(1);
    }   

    int pipe_filefd[2],pipe_outfd[2];
    pipe(pipe_filefd);
    pipe(pipe_outfd);

    int filefd = open(argv[1],O_CREAT | O_WRONLY | O_TRUNC,0644);
    if(filefd == -1) 
        perror("open error");

    //將標準輸入內容輸入管道中
    int n = splice(STDIN_FILENO,NULL,pipe_outfd[1],NULL,LEN,SPLICE_F_MORE | SPLICE_F_MOVE);
    if(n == -1) 
    {   
        perror("splice_1 error");
        exit(1);
    }   

    //將pipe_outfd管道里的數據複製到pipe_filefd管道中
    int ret = tee(pipe_outfd[0],pipe_filefd[1],n,SPLICE_F_NONBLOCK);
    if(ret == -1) 
    {   
        perror("tee error");
        exit(1);
    }   

    //pipe_outfd管道中的數據輸出到標準輸出
    ret = splice(pipe_outfd[0],NULL,STDOUT_FILENO,NULL,n,SPLICE_F_MORE | SPLICE_F_MOVE);
    if(ret == -1) 
    {   
        if(errno == EINVAL)
            printf("----------------\n");
        perror("splice_2 error");
        exit(1);
    }

    //將pipe_filefd管道中的數據輸出到文件中。
    splice(pipe_filefd[0],NULL,filefd,NULL,n,SPLICE_F_MORE | SPLICE_F_MOVE);

    close(filefd);
    close(pipe_filefd[0]);
    close(pipe_filefd[1]);
    close(pipe_outfd[0]);
    close(pipe_outfd[1]);

    return 0;
}

上述代碼有個BUG,就是編譯後運行會出現下面的情況
在這裏插入圖片描述
這裏是splice函數報錯,通過驗證錯誤碼是EINVAL,通過上篇博客我們可以知道這個錯誤碼的含義。
在這裏插入圖片描述
文件系統肯定支持splice函數,我代碼中open也設置了截斷標誌,文件描述符有管道文件描述符,offset參數我傳的是NULL,也不存在隨機訪問,神奇的是我新打開一個終端,再運行就可以了,當我再次編譯後運行又會發生同樣的錯誤。效果如下:
在這裏插入圖片描述
這個就很神奇,有哪位大神看到了知道原因,跪求指點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章