程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 高級I/O函數(3)-tee、fcntl函數,-teefcntl

高級I/O函數(3)-tee、fcntl函數,-teefcntl

編輯:C++入門知識

高級I/O函數(3)-tee、fcntl函數,-teefcntl


tee函數使用

功能描述:tee函數在兩個管道文件描述符之間復制數據,也是零拷貝操作.它不消耗數據,因此源文件描述符仍然可以用於後續的操作.

函數原型:

#include <fcntl.h>
 ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);

函數參數:fd_in和fd_out必須都是管道文件描述符。

返回值:成功時返回在兩個文件描述符之間復制的數據字節數,返回0表示沒有復制任何數據.失敗時返回-1並設置errno.

下面是利用tee函數和splice函數,實現同時輸出數據到終端與文件的程序)的基本功能.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>

int main(int argc,const char* argv[]){
    if(argc<=2){
        printf("usage:%s <file>\n",argv[0]);
        exit(-1);
    }
    
    int filefd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666);
    assert(filefd>=0);
    
    int pipefd_stdout[2];
    int ret=pipe(pipefd_stdout);
    assert(ret!=-1);
    
    int pipefd_file[2];
    ret=pipe(pipefd_file);
    assert(ret!=-1);
    
    /*將標准輸入內容輸入管道文件pipefd_stdout*/
    ret=splice(STDIN_FILENO,NULL,pipefd_stdout[1],NULL,32768,SPLICE_F_MORE
                                    |SPLICE_F_MOVE);
    assert(ret!=-1);
    
    /*將管道pipefd_stdout[0]輸出復制到管道pipefd_file的輸入端*/
    ret=tee(pipefd_stdout[0],pipefd_file[1],32768,SPLICE_F_NONBLOCK);
    assert(ret!=-1);
    /*將管道pipefd_file的輸出定向到文件描述符filefd上*/
    ret=splice(pipefd_file[0],NULL,filefd,NULL,32768,SPLICE_F_MORE|
                                    SPLICE_F_MORE);
    assert(ret!=-1);
    /*將管道pipefd_stdout的輸出定向到標准輸出,其內容與文件中完全一致*/
    ret=splice(pipefd_stdout[0],NULL,STDOUT_FILENO,NULL,32768,SPLICE_F_MORE|
                                        SPLICE_F_MOVE);
    assert(ret!=-1);
    
    close(filefd);
    close(pipefd_file[0]);
    close(pipefd_file[1]);
    close(pipefd_stdout[0]);
    close(pipefd_stdout[1]);
    return 0;
}

fcntl函數的使用

功能描述:常用於控制文件描述符的屬性和行為

函數原型:

#include <fcntl.h>
int fcntl(int fd,int cmd,...);

fd是被操作的文件描述符,cmd參數指定執行何種類型的操作.根據操作類型的不同,該函數可能還需要第三個可選參數.

                           fcntl支持的常用操作及其參數

操作分類 操作 含義 第三個參數的類型 成功時的返回值 復制文件描述符 F_DUPFD 創建一個新的文件描述符,其值大於或等於arg long 新創建的文件描述符的值 F_DUPFD_CLOEXEC 與F_DUPFD相似,不過在創建文件描述符的同時,設置其close_on_exec標志 long 新創建的文件描述符的值 獲取和設置文件描述符的標志 F_GETFD 獲取fd的標志 無 fd的標志 F_SETFD 設置fd的標志 long 0 獲取和設置文件描述符的狀態標志 F_GETFL 獲取fd的狀態標志,這些標志包括可由open系統調用設置的標志(O_CREAT、O_APPEND等)和訪問模式(O_RDONLY、O_WRONLY和O_RDWR) void fd的狀態標志 F_SETFL 設置fd的狀態標志,但部分標志是不能修改的(比如訪問模式標志) long 0 管理信號 F_GETOWN 獲得SIGIO和SIGURG信號的宿主進程的PID或進程組的ID 無 信號的宿主進程或者進程組ID F_SETOWN 設定SIGIO和SIGURG信號的宿主進程的PID和進程組的ID long  0 F_GETSIG 獲取當應用程序被通知fd可讀或可寫時,是哪個信號通知該事件的 無 信號值 F_SETSIG 設置當fd可讀或可寫時,系統應該觸發哪個信號來通知應用程序 long 0 操作管道容量 F_SETPIPE 設置由fd指定的管道的容量 long 0 F_GETPIPE 獲取由fd指定的管道的容量 無 管道容量

 


fcntl函數理解問題

估計fcntl返回失敗-1,O_WRONLY|O_TRUNC不能更改

fcntl的文件狀態有7個:O_RDONLY,O_WRONLY,O_RDWR,O_NONBLOCK,O_APPEND,O_SYNC(異步I/O),O_ASYNC(等待寫完成),
可以更改的標志是O_APPEND,O_NONBLOCK,O_SYNC,O_ASYNC。(沒有O_EXEC等其他的)
O_NONBLOCK:非阻塞I/O,如果read(2)調用沒有可讀的數據,或者如果write(2)操作將阻塞,則read或write調用將返回-1和EAGAIN錯誤。
O_APPEND:強制每次寫(write)操作都將添加在文件大的末尾,相當於open(2)的O_APPEND標志。
O_DIRECT:最小化或去掉reading和writing的緩存影響。系統將企圖避免緩存你的讀或寫的數據,如果不能避免緩存,那麼它將最小化已經被緩存了的數據造成的影響。如果這個標志用的不夠好,將大大降低性能。
O_ASYNC:當I/O可用的時候,允許SIGIO信號發送到進程組,例如:當有數據可讀的時候。
 

fcntl函數的使用問題

fcntl使用結構體的形式如下:
int fcntl(int fd, int cmd, struct flock *lock);如果你是這樣聲明並使用的,應該使用指針的->操作符:
struct flcok *lock;var=fcntl(atoi(argv[1]), F_GETFL, lock);如果你是如下聲明並使用的,應該使用結構體的.操作符:
struct flcok lock;var=fcntl(atoi(argv[1]), F_GETFL, &lock);//用取地址符&傳遞指針參數這個聲明是非指針結構體,通過地址傳值給指針結構體參數,在外部操作上不能用->指針操作符。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved