[Linux]APUE讀書筆記:File I/O

文件描述符:shell

  1. 進程經過文件描述符來操做文件,文件描述符能夠經過open, openat, creat系統調用返回;
  2. shell和其餘應用默認打開標準輸入(STDIN_FILENO),標準輸出(STDOUT_FILENO),標準錯誤(STDERR_FILENO)三個文件描述符。

open和openat函數:數據結構

  1. 文件能夠經過調用open或者openat函數打開或者建立;
  2.  新文件描述符使用最小未使用原則;
  3. TOCTTOU(time of check of time of use)的基本含義:程序是脆弱的,若是它調用兩個基於文件的函數,而且後一個調用依賴於前一個調用的結果。由於這兩個調用不是原子操做,在兩個調用之間文件是能夠被改變的,致使前一個調用的結果失效,錯誤發生。

creat函數:app

  1. creat函數以只寫的方式建立文件;
  2. creat函數徹底能夠用open函數代替:open(path, O_WRONLY | O_CREAT | O_TRUNC, mode)。

lseek函數:
  1. 用於顯式指定被打開文件的偏移量,返回當前文件的新偏移量;
  2. 測試標準輸入是否能夠seek:異步

 1 #include "apue.h"
 2 
 3 int main(void)
 4 {
 5     if (lseek(STDIN_FILENO, 0, SEEK_CUR) == -1) {
 6         printf("canot seek\n");
 7     }
 8     else {
 9         printf("seek OK\n");
10     }
11     exit(0);
12 }
View Code

  3. 因爲文件當前偏移量可能爲負數,lseek的返回值應該和 -1 比較,而不是測試是否小於0;
  4. 設置的當前文件偏移量大於文件長度時,文件中容許造成空洞,空洞不須要存儲空間來存儲;
  5. 在文件中建立一個空洞:async

 1 #include "apue.h"
 2 #include <fcntl.h>
 3 
 4 char buf1[] = "abcdefghij";
 5 char buf2[] = "ABCDEFGHIJ";
 6 
 7 int main(void)
 8 {
 9     int fd;
10 
11     if ((fd = creat("file.hole", FILE_MODE)) < 0) {
12         err_sys("creat error");
13     }
14 
15     if (write(fd, buf1, 10) != 10) {
16         err_sys("buf1 write error");
17     }
18     /*offset now = 10*/
19 
20     if (lseek(fd, 16384, SEEK_SET) == -1) {
21         err_sys("lseek error");
22     }
23     /*offset now = 16384*/
24 
25     if (write(fd, buf2, 10) != 10) {
26         err_sys("buf2 write error");
27     }
28 
29     exit(0);
30 }
View Code

read/write函數:ide

  1. read函數被用於從打開的文件中讀取數據,返回讀取的字節數;
  2. write函數被用於向打開的文件中寫數據,返回寫入的字節數;

I/O效率:
  1. 利用緩衝將標準輸入複製到標準輸出:函數

 1 #include "apue.h"
 2 
 3 #define BUFFSIZE 4096
 4 
 5 int main(void)
 6 {
 7     int n;
 8     char buf[BUFFSIZE];
 9 
10     while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) {
11         if (write(STDOUT_FILENO, buf, n) != n) {
12             err_sys("write error");
13         }
14     }
15     if (n < 0) {
16         err_sys("read error");
17     }
18 
19     exit(0);
20 }
View Code

  2. Linux ext4文件系統,塊大小是4096,緩衝大小最佳值是4096。
文件共享:
  1. 內核使用三個數據結構表示打開的文件:工具

  • 每一個進程在進程表中都有一個記錄項,記錄項中包含一張打開文件描述符的表,與每一個文件描述符相關聯的是:文件描述符標誌和指向文件表項的指針;
  • 內核維護一張全部已打開文件的文件表,每一個文件表包括:文件狀態標誌,當前偏移量,指向文件V節點表項的指針;
  • 每一個已打開文件(或者設備)都有一個V節點結構,Linux只有i節點;

 

原子操做:測試

  1. 任何須要多個函數的操做都不是原子操做;
  2. 調用pread至關於調用lseek後再調用read, 調用pwrite至關於調用lseek後再調用write,可是調用pread/pwrite是原子操做,且當前文件偏移量不更新;

dup和dup2函數:ui

  1. 一個已經存在的文件描述符能夠用dup和dup2複製;
  2. dup返回最小可用文件描述符,dup2用fd2指定新文件描述符,若是fd2已經打開,則先關閉,若是fd2和fd1相等,則直接返回fd2不關閉它;
  3. dup/dup2老是清除新文件描述的close-on-exec標誌;
  4. dup(fd)/fcntl(fd, F_DUPFD, 0),dup2(fd1, fd2)/close(fd2);fcntl(fd, F_DUPFD, fd2);

sync, fsync和fdatasync函數:

  1. sysc函數只將全部修改過的緩衝塊排在寫隊列,而後返回,不等寫磁盤發生;
  2. fsync只對fd單一文件起做用,它等磁盤寫完成後再返回;
  3. fdatasync和fsync相似,可是它不一樣步更新文件屬性,fsync同步更新;

fcntl函數:
  1. fcntl函數能夠改變一個已打開文件的屬性;
  2. fcntl函數有5種不一樣功能:

  • 複製一個已經存在的描述符(cmd = F_DUPFD or F_DUPFD_CLOEXEC);
  • 獲取/設置文件描述符標誌(cmd = F_GETFD or F_SETFD);
  • 獲取/設置文件狀態標誌(cmd = F_SETFL or F_GETFL);
  • 獲取/設置異步I/O全部權(cmd = F_GETOWN or F_SETOWN);
  • 獲取/設置記錄鎖(cmd = F_GETLK, F_SETLK, F_SETLKW);

  3. 打印具體描述符的文件標誌:

 1 #include "apue.h"
 2 #include <fcntl.h>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     int val;
 7     if (argc != 2) {
 8         err_quit("usage: a.out <descriptor#>");
 9     }
10 
11     if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0) {
12         err_sys("fcntl error for fd %d", atoi(argv[1]));
13     }
14     switch(val & O_ACCMODE) {
15     case O_RDONLY:
16         printf("read only");
17         break;
18     case O_WRONLY:
19         printf("write only");
20         break;
21     case O_RDWR:
22         printf("read write");
23         break;
24     default:
25         err_dump("unknow access mode");
26     }
27     if (val & O_APPEND) {
28         printf(",append");
29     }
30     if (val & O_NONBLOCK) {
31         printf(",nonblocking");
32     }
33     if (val & O_SYNC) {
34         printf(",synchronous writes");
35     }
36 #if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
37     if (val & O_FSYNC) {
38         printf(",synchronous writes");
39     }
40 #endif
41     putchar('\n');
42 
43     exit(0);
44 }
View Code

  4. 打開文件描述符的一個或者多個文件狀態標誌:

 1 #include "apue.h"
 2 #include <fcntl.h>
 3 
 4 void set_fl(int fd, int flags)
 5 {
 6     int val;
 7     if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
 8         err_sys("fcntl F_GETFL error");
 9     }
10     val |= flags;
11     if (fcntl(fd, F_SETFL, val) < 0) {
12         err_sys("fcntl F_SETFL error");
13     }
14 }
View Code

ioctl函數:

  1. ioctl函數是I/O操做的萬能工具,尤爲是對終端設備;

/dev/fd:

  1. 假如n是打開的,打開/dev/fd/n至關於複製描述符n;
相關文章
相關標籤/搜索