通過×××年的工做,常用的一些I/O(很重要,由於Linu一切皆文件)函數,之後用到能夠查看下。這段時間不是很忙,僅僅爲了作個筆記整理一下。node
文件I/O和標準I/O庫有的區別:1)文件I/O是系統調用,標準I/O庫是封裝了系統調用的函數庫;2)文件I/O操做的是文件描述符(內核返回,是一個非負整數,其中0,1,2表明標準輸入,標準輸出,標準錯誤),標準I/O操做的是流即就是FILE對象;所以可見標準I/O的移植行更好。說到系統調用,再來講一下,系統調用就是一箇中斷值爲0x80內核實現的一箇中斷。這一篇主要記錄一下對應文件I/O的一些系統調用。ios
一、打開文件shell
int open(const char *pathname, int flag,/*mode_t mode*/)/*成功返回文件描述符*/緩存
pathname:要打開或建立文件的名字,系統規定了一個最大長度;異步
flag:O_RDONLY 只讀打開。O_WRONLY 只寫打開。O_RDWR 讀寫打開。socket
O_APPEND 每次寫時追加到文件尾部。ide
O_CREAT 若無文件,則建立它。函數
O_EXEL 若是同時指定了O_CREAT,文件已經存在,則會出錯。spa
O_TRUNC 文件存在,併爲只讀或只寫打開,則將長短截取爲0。命令行
O_NOCTTY 若是是終端設備,則不將該設備分配做爲此進程的控制終端。
O_NONBLOCK 將一個FIFO、一個塊特殊文件或一個字符文件設置爲非阻塞模式。
O_DSYNC、O_RSYNC、O_SYNC三個不是很理解,之後用到再深刻理解。
mode:可又可無,意思就是設置用戶權限,組權限,其餘用戶權限 ,例如:777:全權限讀、寫、可執行。
二、creat建立文件
int creat( const char *pathname, mode_t mode);/*成功返回文件描述符*/
參數說明通open函數;
此函數等價於:open( pathname,O_WRONLY| O_CREAT|O_TRUNC,mode);
三、close關閉一個打開文件
int close(int filedes);
關閉一個文件還會釋放加在此文件上的記錄鎖;當一個進程終止後,自動關閉文件,因此不用顯示的調用close去關閉此文件。
四、設置當前文件偏移量lseek函數
off_t lseek(int filedes, off_t offset ,int whence);/*成功返回新的文件偏移量*/
參數offset和whence有關,解釋以下:
SEEK_SET:將文件的偏移量設置距文件開始處offset個字節。
SEEK_CUR:將文件的偏移量設置當前值加上offset,offset可正或負。
SEEK_END:將文件的偏移量設置爲文件長度加offset,offset可正可負。
*能夠用lseek(fd,0,SEEK_CUR),若是返回值爲-1說明沒有設置偏移量,不然設置了偏移量。
五、從文件中讀數據read函數
ssize_t read(int filedes,void *buf,size_t nbytes);/*成功返回讀的字節數,如已經到文件結尾返回0,出錯返回-1*/
六、給打開的文件寫數據write
ssize_t write(int filedes,const void *buf,size_t nbytes);/*成功返回寫的字節數,失敗返回-1*/
若是open的時候指定了O_APPEND參數,則每次寫以前,將文件偏移量設置到結尾處。在一次成功後,便宜量增長實際寫的字節數。
七、原子操做函數pread和pwrite函數
其實用open函數中的O_APPEND參數就能夠實現原子操做,每次write都是在文件尾部。
ssize_t pread(int fd,void *buf,size_t count,off_t offset);
ssize_t pwrite(int fd,const void *buf,size_t count,off_t offset);
至關於順序調用lseek和read或write
八、複製一個現有的文件描述符dup和dup2
int dup(int filedes);
int dup2(int filedes,int filedes2 );
dup返回當前可用的最小文件描述符的值:dup(1)返回3,3共享1
dup2若是兩個參數相等返回filedes2,不然,filedes共享filedes2並關閉filedes2。
舉一個前段時間開發串口進zebra命令行的例子:
int config_console_para(int iConsoleFd);/*modified by zhaoxiaohu*/ /*added by zhaoxiaohu for console to vty*/ struct vty *vty_console_create( char *dev ) { int fd; int iRet; struct vty *vty; fd = open( dev, O_RDWR, 0644 ); if( fd < 0 ) { printf( "error: open console %s error.\r\n", dev ); return NULL; } iRet = config_console_para(fd); if(0 != iRet) { printf("console para set error.\r\n"); } vty = vty_get_new(); if( vty == NULL ) return NULL; vty->fd = fd; vty->type = VTY_CONSOLE; strcpy( vty->address, "Console" ); vty->node = LOGIN_NODE; vty->fail = 0; vty_clear_buf( vty ); vty->status = VTY_NORMAL; vty_hello( vty ); vty_prompt( vty ); buffer_flush_all( vty->obuf, vty->fd ); /* Add read/write thead */ vty_event( VTY_WRITE, vty ); vty_event( VTY_READ, vty ); return vty; } /*b-console config added by zhaoxiaohu,2018-12-19*/ /*配置串口參數*/ int config_console_para(int iConsoleFd) { struct termios tConsolePara; if (iConsoleFd < 3 ) { printf("fd is error.\r\n"); return -1; } if(tcgetattr(iConsoleFd,&tConsolePara) != 0) { printf("get console para error.\r\n"); return -1; } tConsolePara.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG); tConsolePara.c_cc[VERASE] = 1; if(tcsetattr(iConsoleFd,TCSANOW,&tConsolePara) != 0) { printf("config console para error.\r\n"); return -1; } if( cfsetispeed(&tConsolePara,B115200) != 0 )/*設置爲115200Bps*/ { printf("config console para error.\r\n"); return -1; } if( cfsetospeed(&tConsolePara,B115200) != 0 )/*設置爲115200Bps*/ { printf("config console para error.\r\n"); return -1; } return 0; } /*e-console config added by zhaoxiaohu,2018-12-19*/ /*b-added by zhaoxiaohu for console to connect vty shell*/ void console_connect_vty(void ) { struct vty *vty; int iConsoleFd, iRet; vty = vty_console_create("/dev/console"); g_pVty = vty; g_iConsoleFd = vty->fd; iConsoleFd = vty->fd; dup2(iConsoleFd,0);/*close 0,1,2,共享到串口*/ dup2(iConsoleFd,1);/**/ dup2(iConsoleFd,2);/**/ setvbuf(stdout,NULL,_IONBF,0);/*set stdout no buffer,printf to console .added by zhaoxiaohu-2019.4.10*/ struct timeval time_now; struct timeval *time_wait; while(1) { #if 1 time_now.tv_sec = vty->v_timeout; time_now.tv_usec = 0; if( time_now.tv_sec > 0 ) time_wait = &time_now; else time_wait = NULL; iRet = select( iConsoleFd + 1, &vty->read_set, &vty->write_set, NULL, time_wait ); if( iRet <= 0 ) { /* error: close vty */ if( iRet < 0 ) break; /* rc == 0, timeout ! console timeout */ if( vty->type == VTY_CONSOLE ) { vty_timeout( vty ); continue; } else { vty_timeout( vty ); break; } } #endif if( FD_ISSET( iConsoleFd, &vty->read_set ) ) vty_read( vty ); if( FD_ISSET( iConsoleFd, &vty->write_set ) ) vty_flush( vty ); /* console can't close */ if( vty->type == VTY_CONSOLE ) continue; if( vty->status == VTY_CLOSE ) break; } return; } /*e-added by zhaoxiaohu for console to connect vty shell*/
九、改變打開文件的性質函數fcntl
int fcntl(int filedes,int cmd,/*int arg*/,/*flock記錄鎖*/)
函數有五種功能經過設置cmd:
1)複製一個現存的描述符(F_DUPFD);
dup(filed);/*等效於*/ fcntl(filed,F_DUPFD,0); dup2(filed,filed2); /*等效於*/ close(filed2); fcntl(filed,F_DUPFD,filed2); /*dup2 和close+fcntl區別是:前者是原子操做,後者不是*/
2)獲取或設置文件描述符標記(F_GETFD或F_SETFD);
3) 獲取或設置文件描述符標誌(F_GETFL或F_SETFL),能夠改變的幾個標誌:O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC、O_ASYNC;
4) 獲取或設置文件異步I/O全部權(F_GETOWN或F_SETOWN),獲取或設置接收SIGIO、SIGURG信號的進程ID或進程組ID;
5)獲取或設置記錄鎖(F_GETLK、F_SETLK或F_SETLKW),經過結構體flock。
十、I/0操做的雜貨鋪ioctl函數
不能用上面函數操做的文件均可以用ioctl操做
int ioctl(int filedes,int request ,/*void *arg*/)
功能不少,大體分爲:1)套接口2)文件操做3)接口操做4)arp高速緩存操做5)路由表操做6)流系統。
舉一個前段時間工做中用開發靜態路由,查詢arp緩存表的例子:
/*b-added by zhaoxiaohu to serch ip at arp cache*/ /*定義結構體*/ typedef struct tArpTable{ struct tArpTable *pNext; unsigned char data[0]; }*ptVlanIpDev; ptVlanIpDev g_ptVlanIpDevTable = NULL; /*顯示交換芯片添加的虛接口,vlan ip*/ void vlanIpDevTableDisplayAll() { ptVlanIpDev pTemp = g_ptVlanIpDevTable; while(pTemp) { printf("%s\r\n",pTemp->data); pTemp = pTemp->pNext; } } /*清除虛接口表*/ void arpTableClear() { ptVlanIpDev pTemp = NULL; while(g_ptVlanIpDevTable) { pTemp = g_ptVlanIpDevTable; g_ptVlanIpDevTable = pTemp->pNext; free(pTemp); pTemp = NULL; } } /*獲取虛接口*/ int get_vlan_ip_dev() { unsigned char ucBuf[256] = {0}; FILE *fp; fp = popen("find /sys/class/net/ -name sw.*", "r"); if( NULL == fp ) { return -1; } arpTableClear(); while( fgets( ucBuf, sizeof(ucBuf), fp ) ) { ptVlanIpDev pTemp = NULL; if( NULL == (pTemp = (ptVlanIpDev)calloc(1,sizeof(struct tArpTable) + sizeof(ucBuf) )) ) continue; memcpy( pTemp->data,ucBuf,strlen(ucBuf) ); pTemp->pNext = g_ptVlanIpDevTable; g_ptVlanIpDevTable = pTemp; memset( ucBuf,0,sizeof(ucBuf) ); } pclose(fp); return OK; } int ipnet_arp_for_cache( ) { int sfd,ret; unsigned char *ucMac; unsigned char ucIpAddrStr[32] = {0}; struct arpreq arp_req; struct sockaddr_in *sin; get_vlan_ip_dev(); ptVlanIpDev pTemp = g_ptVlanIpDevTable; ip2Str( g_ArpFindIpAddr, ucIpAddrStr );/*要查詢的ip*/ while(pTemp) /*遍歷全部的虛接口*/ { sin = ( struct sockaddr_in * )&( arp_req.arp_pa ); memset( &arp_req, 0, sizeof(arp_req) ); sin->sin_family = AF_INET; inet_pton( AF_INET, ucIpAddrStr, &(sin->sin_addr) ); strncpy( arp_req.arp_dev, pTemp->data+15,strlen(pTemp->data+15)-1 ); sfd = socket( AF_INET, SOCK_DGRAM, 0 ); ret = ioctl( sfd, SIOCGARP, &arp_req ); if (ret < 0) { goto nextNode; } if ( arp_req.arp_flags & ATF_COM ) /*找到ip對應的mac地址*/ { ucMac = (unsigned char *)arp_req.arp_ha.sa_data; // printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", // ucMac[0], ucMac[1], ucMac[2], ucMac[3], ucMac[4], ucMac[5]); memcpy( gArpFindMac, ucMac, 6 ); } else { // printf("MAC: Not in the ARP cache.\n"); } nextNode: pTemp = pTemp->pNext; } return OK; } /*e-added by zhaoxiaohu to serch ip at arp cache*/