1. gzyueqian
      13352868059
      首頁 > 新聞中心 > > 正文

      linux基礎復習(6)文件I/O操作

      更新時間: 2008-08-22 13:23:16來源: 粵嵌教育瀏覽量:1059

        不帶緩存的文件I/O 操作,主要用到5 個函數:open、read、write、lseek和close。這里的不帶緩存是指每一個函數都只調用系統中的一個函數(不理解這句話的含義)。這些函數雖然不是ANSI C的組成部分,但是是POSIX 的組成部分。
        open函數語法要點
      |-- #i nclude // 提供類型pid_t的定義
      所需頭文件----|-- #i nclude
      |-- #i nclude
      函數原型 int open(const char *pathname,flags,int perms)
      pathname 被打開的文件名(可包括路徑名)
      O_RDONLY:只讀方式打開文件
      O_WRONLY:可寫方式打開文件
      O_RDWR:讀寫方式打開文件
      O_CREAT:如果該文件不存在,就創建一個新的文件,并用第三個參數為其設置權限
      O_EXCL:如果使用O_CREAT時文件存在,則可返回錯誤消息。這一
      函數傳入值 參數可測試文件是否存在
      O_NOCTTY:使用本參數時,如文件為終端
      終端不可用open()系統調用的那個進程的控制終端
      O_TRUNC:如文件已經存在,并且以只讀或只寫成功打開,那么會先
      全部刪除文件中原有數據
      O+APPEND:以添加方式打開文件,在打開文件的同時,文件指針指
      向文件的末尾
      perms 被打開文件的存取權限,為8進制表示法
      函數返回值 成功:返回文件描述符
      失敗:-1

      補述:文件描述符
      對于Linux 而言,所有對設備和文件的操作都使用文件描述符來進行的。文件描述符
      是一個非負的整數,它是一個索引值,并指向內核中每個進程打開文件的記錄表。當打開一
      個現存文件或創建一個新文件時,內核就向進程返回一個文件描述符;當需要讀寫文件時,
      也需要把文件描述符作為參數傳遞給相應的函數。
      通常,一個進程啟動時,都會打開3 個文件:標準輸入、標準輸出和標準出錯處理。這
      3 個文件分別對應文件描述符為0、1 和2(也就是宏替換STDIN_FILENO、STDOUT_FILENO
      和STDERR_FILENO)。
      基于文件描述符的I/O 操作雖然不能移植到類Linux 以外的系統上去(如Windows),但它
      往往是實現某些I/O操作的惟一途徑,如Linux中低級文件操作函數、多路I/O、TCP/IP套接字
      編程接口等。同時,它們也很好地兼容POSIX標準,因此,可以很方便地移植到任何POSIX平
      臺上。基于文件描述符的I/O操作是Linux中常用的操作之一。

      read函數語法要點
      所需頭文件 #i nclude
      函數原型 ssize_t read(int fd,void *buf,size_t count)
      fd:文件描述符
      函數傳入值 buf:指定存儲器讀出數據的緩函數傳入值 沖區
      count:指定讀出的字節數
      成功:讀到的字節數
      函數返回值 0:已到達文件尾
      -1:出錯




      write函數語法要點
      所需頭文件 #i nclude
      函數原型 ssize_t write(int fd,void *buf,size_t count)
      fd:文件描述符
      函數傳入值 buf:指定存儲器寫入數據的緩函數傳入值 沖區
      count:指定讀出的字節數
      函數返回值 成功:已寫的字節數
      -1:出錯


      lseek函數語法要點
      所需頭文件 #i nclude
      #i nclude
      函數原型 off_t lseek(int fd,off_t offset,int whence)
      fd:文件描述符
      函數傳入值 offset:偏移量,每一讀寫操作所需要移動的距離
      單位是字節的數量,可正可負(向前移,向后移)

      whence: SEEK_SET:當前位置為文件的開頭,新位置為偏移量的大小
      當前位置 SEEK_CUR:當前位置為文件指針的位置,新位置為當前位置加上偏移
      的基點 SEEK_END:當前位置為文件的結尾,新位置為文件的大小加上偏移
      函數返回值 成功:文件的當前位移
      -1:出錯

      /*打開,關閉,讀寫文件.c*/
      #i nclude unistd.h>
      #i nclude sys/types.h>
      #i nclude sys/stat.h>
      #i nclude fcntl.h>
      #i nclude stdlib.h>
      #i nclude stdio.h>
      int main(void)
      {
      int fd; //文件描述符
      int i,size,len;
      char *buf="Writing to this file!";
      char buf_r[10];
      len = strlen(buf);
      /*調用open函數,以可讀寫的方式打開,注意選項可以用“|”符號連接*/
      if((fd = open("/tmp/hello.c", O_CREAT | O_TRUNC | O_WRONLY , 0600 ))0){
      perror("open:");
      exit(1);
      }
      else{
      printf("Open file: hello.c %d\n",fd);
      }

      /*調用write函數,將buf中的內容寫入到打開的文件中*/
      if((size = write( fd, buf, len)) 0){
      perror("write:");
      exit(1);
      }
      else
      printf("Write:%s\n",buf);
      /*調用lsseek函數將文件指針移到文件起始,并讀出文件中的10個字節*/
      lseek( fd, 0, SEEK_SET );
      if((size = read( fd, buf_r, 10))0){
      perror("read:");
      exit(1);
      }
      else
      printf("read form file:%s\n",buf_r);

      if( close(fd) 0 ){
      perror("close:");
      exit(1);
      }
      else
      printf("Close hello.c\n");
      exit(0);
      }


      當多個用戶共同使用、操作一個文件的情況,這時,Linux 通常采用的方法是給文件上鎖,來避免共享的資源產生競爭的狀態。
      文件鎖包括建議性鎖和強制性鎖。建議性鎖要求每個上鎖文件的進程都要檢查是否有鎖存在,并且尊重已有的鎖。在一般情況下,內核和系統都不使用建議性鎖。強制性鎖是由內核執行的鎖,當一個文件被上鎖進行寫入操作的時候,內核將阻止其他任何文件對其進行讀寫操作。采用強制性鎖對性能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。在Linux 中,實現文件上鎖的函數有lock和fcntl,其中flock用于對文件施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強制鎖。同時,fcntl還能對文件的某一記錄進行
      上鎖,也就是記錄鎖。記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共享鎖,它能夠使多個進程都能在
      文件的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時刻只能有一個進程在文件的某個部分上建立寫入鎖。當然,在文件的同一部分不能同時建立讀取鎖和寫入鎖。
      fcntl函數格式

      fcntl函數可以改變已經打開文件的性質。
      #i nclude
      #i nclude
      #i nclude
      int fcntl(int filedes, int cmd, ... ) ;
      返回:若成功則依賴于cmd(見下),若出錯為- 1。


      f c n t l函數有五種功能:
      n 復制一個現存的描述符, 新文件描述符作為函數值返(c m d=F_DUPFD)。
      n 獲得/設置文件描述符標記,對應于filedes 的文件描述符標志作為函數值返回.(c m d = F_GETFD或F_SETFD)。
      n 獲得/設置文件狀態標志,對應于filedes 的文件狀態標志作為函數值返回。(c m d = F_GETFL或F_SETFL)。
      n 獲得/設置異步I / O有權(c m d = F_GETOWN或F_SETOWN)。
      n 獲得/設置記錄鎖(c m d = F_SETLK , F_SETLKW)。

      關于加鎖和解鎖區域的說明還要注意下列各點:
      l 該區域可以在當前文件尾端處開始或越過其尾端處開始,但是不能在文件起始位置之前開始或越過該起始位置。
      l 如若l_len為0,則表示鎖的區域從其起點(由l_start和l_whence決定)開始直至可能位置為止。也就是不管添寫到該文件中多少數據,它都處于鎖的范圍。
      l 為了鎖整個文件,通常的方法是將l_start說明為0,l_whence說明為SEEK_SET,l_len說明為0。

      實例:

      /*fcntl_write.c測試文件寫入鎖主函數部分*/
      #i nclude unistd.h>
      #i nclude sys/file.h>
      #i nclude sys/types.h>
      #i nclude sys/stat.h>
      #i nclude stdio.h>
      #i nclude stdlib.h>
      /*lock_set函數*/
      void lock_set(int fd, int type)
      {
      struct flock lock;
      lock.l_whence = SEEK_SET;//賦值lock結構體
      lock.l_start = 0;
      lock.l_len =0;
      while(1)
      {
      lock.l_type = type;
      /*根據不同的type值給文件上鎖或解鎖*/
      if((fcntl(fd, F_SETLK, &lock)) == 0)
      {
      if( lock.l_type == F_RDLCK )
      printf("read lock set by %d\n",getpid());
      else if( lock.l_type == F_WRLCK )
      printf("write lock set by %d\n",getpid());
      else if( lock.l_type == F_UNLCK )
      printf("release lock by %d\n",getpid());
      return;
      }
      /*判斷文件是否可以上鎖*/
      fcntl(fd, F_GETLK,&lock);
      /*判斷文件不能上鎖的原因*/
      if(lock.l_type != F_UNLCK)
      {
      /*/該文件已有寫入鎖*/
      if( lock.l_type == F_RDLCK )
      printf("read lock already set by %d\n",lock.l_pid);
      /*該文件已有讀取鎖*/
      else if( lock.l_type == F_WRLCK )
      printf("write lock already set by %d\n",lock.l_pid);
      getchar();
      }
      }
      }
      int main(void)
      {
      int fd;
      /*首先打開文件*/
      fd=open("hello",O_RDWR | O_CREAT, 0666);
      if(fd 0)
      {
      perror("open");
      exit(1);
      }
      /*給文件上寫入鎖*/
      lock_set(fd, F_WRLCK);
      getchar();
      /*給文件接鎖*/
      lock_set(fd, F_UNLCK);
      getchar();
      close(fd);
      exit(0);
      }
      開兩個終端分別運行,可看到先運行的那個終端,成功上鎖,后運行的那個無效。可見寫入鎖是互斥鎖,一個時候只能有一個寫入鎖存在
      select 實現I/O復用
      I/O處理的五種模型
      ① 阻塞I/O模型:若所調用的I/O函數沒有完成相關的功能就會使進程掛起,直到相關數據到達才會返回。如:終端、網絡設備的訪問。
      ② 非阻塞模型:當請求的I/O操作不能完成時,則不讓進程休眠,而且返回一個錯誤。如:open、read、write訪問。
      ③ I/O多路轉接模型:如果請求的I/O 操作阻塞,且他不是真正阻塞I/O,而且讓其中的一個函數等待,在這期間, I/O還能進行其他操作。如:select函數。
      ④ 信號驅動I/O模型:在這種模型下,通過安裝一個信號處理程序,系統可以自動捕獲特定信號的到來,從而啟動I/O。
      ⑤ 異步I/O模型:在這種模型下,當一個描述符已準備好,可以啟動I/O時,進程會通知內核。由內核進行后續處理,這種用法現在較少。
      select函數
      傳向select的參數告訴內核:
      (1) 我們所關心的描述符。
      (2) 對于每個描述符我們所關心的條件(是否讀一個給定的描述符?是否想寫一個給定的描述符?是否關心一個描述符的異常條件?)。
      (3) 希望等待多長時間(可以永遠等待,等待一個固定量時間,或完全不等待)。
      從s e l e c t返回時,內核告訴我們:
      (1) 已準備好的描述符的數量。
      (2) 哪一個描述符已準備好讀、寫或異常條件。
      #i nclude /* fd_set data type */
      #i nclude /* struct timeval */
      #i nclude /* function prototype might be here */
      int select (int numfds, fd_set *readfds,
      fd_set *writefds, fd_set *exceptfds, struct timeval * timeout) ;
      返回:準備就緒的描述符數,若超時則為0,若出錯則為- 1。
      timeout值:
      n NULL:永遠等待,直到捕捉到信號或文件描述符已準備好為止;
      n 具體值: struct timeval 類型的指針,若等待為timeout時間還沒有文件描述符準備好,就立即返回;
      n 0:從不等待,測試所有指定 的描述符并立即返回;
      先說明一個參數,它指定愿意等待的時間。
      struct timeval
      {
      long tv_sec; /* seconds */
      long tv_usec; /* and microseconds */
      };

      select函數根據希望進行的文件操作對文件描述符進行分類處理,這里,對文件描述符的處理主要設計4個宏函數:
      FD_ZERO(fd_set *set) 清除一個文件描述符集;
      FD_SET(int fd, fd_set *set) 將一個文件描述符加入文件描述符集中;
      FD_CLR(int fd, fd_set *set) 將一個文件描述符從文件描述符集中清除;
      FD_ISSET(int fd, fd_set *set) 測試該集中的一個給定位是否有變化;
      在使用select函數之前,首先使用FD_ZERO和FD_SET來初始化文件描述符集,并使用select函數時,可循環使用FD_ISSET測試描述符集, 在執行完成對相關的文件描述符后, 使用FD_CLR來清除描述符集。
      實例


      /*select.c*/
      #i nclude fcntl.h>
      #i nclude stdio.h>
      #i nclude unistd.h>
      #i nclude stdlib.h>
      #i nclude sys/time.h>
      int main(void)
      {
      int fds[2];
      char buf[7];
      int i,rc,maxfd;
      fd_set inset1,inset2;
      struct timeval tv;

      if((fds[0] = open ("hello1", O_RDWR|O_CREAT,0666))0)
      perror("open hello1");
      if((fds[1] = open ("hello2", O_RDWR|O_CREAT,0666))0)
      perror("open hello2");
      if((rc = write(fds[0],"Hello!\n",7)))
      printf("rc=%d\n",rc);

      lseek(fds[0],0,SEEK_SET);
      maxfd = fds[0]>fds[1] ? fds[0] : fds[1];
      //初始化讀集合 inset1,并在讀集合中加入相應的描述集
      FD_ZERO(&inset1);
      FD_SET(fds[0],&inset1);
      //初始化寫集合 inset2,并在寫集合中加入相應的描述集
      FD_ZERO(&inset2);
      FD_SET(fds[1],&inset2);
      tv.tv_sec=2;
      tv.tv_usec=0;
      // 循環測試該文件描述符是否準備就緒,并調用 select 函數對相關文件描述符做相應操作
      while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2))
      {
      if(select(maxfd+1,&inset1,&inset2,NULL,&tv)0)
      perror("select");
      else{
      if(FD_ISSET(fds[0],&inset1))
      {
      rc = read(fds[0],buf,7);
      if(rc>0)
      {
      buf[rc]='\0';
      printf("read: %s\n",buf);
      }else
      perror("read");
      }
      if(FD_ISSET(fds[1],&inset2))
      {
      rc = write(fds[1],buf,7);
      if(rc>0)
      {
      buf[rc]='\0';
      printf("rc=%d,write: %s\n",rc,buf);
      }else
      perror("write");
      sleep(10);
      }
      }
      }
      exit(0);
      }

      免費預約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 色久国产第一页 | 天天免費国产在线观看 | 亚洲精品国自产拍在线观看 | 久久超级碰碰视频久久 | 在线能看三级网站 | 伊人久久大香线蕉一区 |