Linux系統編程:簡單文件IO操作


使用Linux的文件API,經常看見一個東西,叫做文件描述符.

什么是文件描述符?

(1)文件描述符其實實質是一個數字,這個數字在一個進程中表示一個特定的含義,當我們open打開一個文件時,操作系統在內存中構建了一些數據結構來表示這個動態文件,然后返回給應用程序一個數字作為文件描述符,這個數字就和我們內存中維護這個動態文件的這些數據結構掛鈎綁定上了,以后我們應用程序如果要操作這一個動態文件,只需要用這個文件描述符進行區分。

(2)文件描述符就是用來區分一個程序打開的多個文件的。

(3)文件描述符的作用域就是當前進程,出了當前進程這個文件描述符就沒有意義了

(4)文件描述符fd的合法范圍是0或者一個正數,不可能是一個負數

(5)open返回的fd必須記錄好,以后向這個文件的所有操作都要靠這個fd去對應這個文件,最后關閉文件時也需要fd去指定關閉這個文件。如果在我們關閉文件前fd丟了,那么這個文件就沒法關閉了也沒法讀寫了

1)打開與讀取文件

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 
 7 int main(int argc, char const *argv[]) {
 8 
 9     int fd = -1; //文件描述符
10 
11     //打開文件
12     fd = open( "ghostwu.txt", O_RDWR );
13 
14     if ( -1 == fd ) {
15         printf("文件打開失敗\n");
16     }else {
17         printf("文件打開成功,fd=%d\n", fd );
18     }
19 
20     //讀取文件
21     int count = 0;
22     char buf[20];
23     count = read( fd, buf, 50 );
24     if ( -1 == count ) {
25         printf("文件讀取失敗\n");
26     }else {
27         printf("文件讀取成功,實際讀取的字節數目為:%d\n內容為%s\n", count, buf );
28     }
29 
30     //關閉文件
31     close( fd );
32 
33     return 0;
34 }

需要在當前目錄下存在ghostwu.txt這個文件,否則打開的時候失敗,這里涉及2個api

int open(const char *pathname, int flags);

open非常簡單,第一個參數就是文件路徑, 第二個是文件模式,在man手冊中還提供了其他幾種方式。

ssize_t read(int fd, void *buf, size_t count);

第一個參數為文件描述符,就是open返回的那個值

第二個參數buf用來存儲從文件中讀取的內容

第三個參數,表示希望從文件中讀取的內容( 注:這個count數字可以隨便給,最終以返回的實際數目(read的返回值)為准

2)打開與寫入文件

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1; //文件描述符
11 
12     //打開文件
13     fd = open( "ghostwu.txt", O_RDWR );
14 
15     if ( -1 == fd ) {
16         printf("文件打開失敗\n");
17     }else {
18         printf("文件打開成功,fd=%d\n", fd );
19     }
20 
21     //寫文件
22     char buf[] = "I love Linux, Linux is very very good!!!";
23     int count = 0;
24     count = write( fd, buf, strlen( buf ) );
25     if ( -1 == count ) {
26         printf("文件寫入失敗\n");
27     }else {
28         printf("文件寫入成功,實際寫入的字節數目為:%d\n", count);
29     }
30 
31     //關閉文件
32     close( fd );
33 
34     return 0;
35 }

ssize_t write(int fd, const void *buf, size_t count);

第一個參數為文件描述符,就是open返回的那個值

第二個參數buf用來存儲寫入的內容

第三個參數,表示希望寫入的文件大小

3)open的一些flag參數

1,只讀與只寫權限

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 
 7 int main(int argc, char const *argv[]) {
 8 
 9     int fd = -1; //文件描述符
10 
11     //打開文件, O_RDONLY:只讀權限,打開之后的文件只能讀取,不能寫入
12     //打開文件, O_WRONLY:只寫權限,打開之后的文件只能寫入,不能讀取
13     // fd = open( "ghostwu.txt", O_RDONLY );
14     fd = open( "ghostwu.txt", O_WRONLY );
15 
16     if ( -1 == fd ) {
17         printf("文件打開失敗\n");
18     }else {
19         printf("文件打開成功,fd=%d\n", fd );
20     }
21 
22     //讀取文件
23     int count = 0;
24     char buf[41];
25     count = read( fd, buf, 38 );
26     if ( -1 == count ) {
27         printf("文件讀取失敗\n");
28     }else {
29         printf("文件讀取成功,實際讀取的字節數目為:%d\n內容為%s\n", count, buf );
30     }
31 
32     //關閉文件
33     close( fd );
34 
35     return 0;
36 }

2,清空與追加

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1; //文件描述符
11 
12     //打開文件
13     //在O_RDWR模式下,對於一個已經存在的文件,且有內容,那么寫入文件會覆蓋對應大小的源文件內容【不是完全覆蓋】
14     // fd = open( "ghostwu.txt", O_RDWR );
15     //在具有寫入權限的文件中,使用O_TRUNC 會先把原來的內容清除,再寫入新的內容
16     // fd = open( "ghostwu.txt", O_RDWR | O_TRUNC );
17     //在具有寫入權限的文件中,使用O_APPEND 會把新內容追加到原來內容的后面
18     // fd = open( "ghostwu.txt", O_RDWR | O_APPEND );
19 
20     //在具有寫入權限的文件中,使用O_APPEND和O_TRUNC O_TRUNC起作用,會把原來的內容清除,再寫入新的內容
21     fd = open( "ghostwu.txt", O_RDWR | O_APPEND | O_TRUNC );
22 
23     if ( -1 == fd ) {
24         printf("文件打開失敗\n");
25         return -1;
26     }else {
27         printf("文件打開成功,fd=%d\n", fd );
28     }
29 
30     //寫文件
31     char buf[] = "new content";
32     int count = 0;
33     count = write( fd, buf, strlen( buf ) );
34     if ( -1 == count ) {
35         printf("文件寫入失敗\n");
36         return -1;
37     }else {
38         printf("文件寫入成功,實際寫入的字節數目為:%d\n", count);
39     }
40 
41     //關閉文件
42     close( fd );
43 
44     return 0;
45 }

3,文件存在已否,創建文件與設置權限

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <errno.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1;
11 
12     // fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL );
13 
14     /*
15         文件不存在:
16             創建這個文件 並打開成功
17         文件存在:
18             再次運行時(文件已經創建成功,存在了), 這時打開失敗
19     */
20     // fd = open( "ghostwu.txt", O_RDWR | O_CREAT );
21 
22     fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL, 666 );
23 
24     if( -1 == fd ) {
25         printf("文件打開失敗,錯誤號:%d\n", errno );
26         perror( "open" );
27         return -1;
28     }else {
29         printf("文件打開成功\n");
30     }
31 
32     close( fd );
33 
34     return 0;
35 }

上面用到了一個函數perror,errno和perror:

1)errno就是error number,意思就是錯誤號碼。linux系統中對各種常見錯誤做了個編號,當函數執行錯誤時,函數會返回一個特定的errno編號來告訴我們這個函數到底哪里錯了

2)errno是由操作系統來維護的一個全局變量,操作系統內部函數都可以通過設置errno來告訴上層調用者究竟剛才發生了一個什么錯誤

3)errno本身實質是一個int類型的數字,每個數字編號對應一種錯誤。當我們只看errno時只能得到一個錯誤編號數字,並不知道具體錯在哪里,所以:linux系統提供了一個函數perror(意思print error),perror函數內部會讀取errno並且將這個不好認的數字直接給轉成對應的錯誤信息字符串,然后打印出來

4,lseek用來移動文件內部指針

簡單應用:統計文件大小

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <errno.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     if ( argc != 2 ) {
11         printf("usage:%s %s\n", argv[0], "filename");
12         return -1;
13     }
14 
15     int fd = -1;
16 
17     fd = open( argv[1], O_RDWR );
18 
19     if( -1 == fd ) {
20         printf("文件打開失敗,錯誤號:%d\n", errno );
21         perror( "open" );
22         return -1;
23     }else {
24         printf("文件打開成功\n");
25     }
26 
27     //把指針移動到文件末尾,就是文件的大小
28     int count = lseek( fd, 0, SEEK_END );
29 
30     printf("文件大小為%d\n", count);
31 
32     close( fd );
33     return 0;
34 }

------------------------------------------分割線------------------------------------------

一、同一個進程,多次打開同一個文件,然后讀出內容的結果是: 分別讀【我們使用open兩次打開同一個文件時,fd1和fd2所對應的文件指針是不同的2個獨立的指針】

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <errno.h>
 6 #include <unistd.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd1 = -1;
11     int fd2 = -1;
12     char buf1[20] = {0};
13     char buf2[20] = {0};
14     int count1 = 0;
15     int count2 = 0;
16 
17     fd1 = open( "ghostwu.txt", O_RDWR );
18 
19     if ( -1 == fd1 ) {
20         printf("文件打開失敗\n");
21         perror( "open" );
22         return -1;
23     }else {
24         printf("文件打開成功,fd1=%d\n", fd1);
25     }
26 
27     count1 = read( fd1, buf1, 5 );
28     if ( -1 == count1 ) {
29         printf( "文件讀取失敗\n" );
30         perror( "read" );
31     }else {
32         printf( "文件讀取成功,讀取的內容是%s\n", buf1 );
33     }
34 
35     fd2 = open( "ghostwu.txt", O_RDWR );
36 
37     if ( -1 == fd1 ) {
38         printf("文件打開失敗\n");
39         perror( "open" );
40         return -1;
41     }else {
42         printf("文件打開成功,fd2=%d\n", fd1);
43     }
44 
45     count2 = read( fd2, buf2, 10 );
46     if ( -1 == count2 ) {
47         printf( "文件讀取失敗\n" );
48         perror( "read" );
49     }else {
50         printf( "文件讀取成功,讀取的內容是%s\n", buf2 );
51     }
52 
53     close( fd1 );
54     close( fd2 );
55 
56     return 0;
57 }

 二、同一個進程,多次打開同一個文件,然后寫入內容的結果是: 分別寫,當使用O_APPEND,就是接着寫

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <errno.h>
 6 #include <unistd.h>
 7 #include <string.h>
 8 
 9 int main(int argc, char const *argv[]) {
10 
11     int fd1 = -1;
12     int fd2 = -1;
13     char buf1[] = "ghost";
14     char buf2[] = "wu";
15     int count1 = 0;
16     int count2 = 0;
17 
18     fd1 = open( "ghostwu.txt", O_RDWR );
19 
20     if ( -1 == fd1 ) {
21         printf("文件打開失敗\n");
22         perror( "open" );
23         return -1;
24     }else {
25         printf("文件打開成功,fd1=%d\n", fd1);
26     }
27 
28     count1 = write( fd1, buf1, strlen( buf1 ) );
29     if ( -1 == count1 ) {
30         printf( "文件寫入失敗\n" );
31         perror( "write" );
32     }else {
33         printf( "文件寫入成功,寫入的內容是%s\n", buf1 );
34     }
35 
36     fd2 = open( "ghostwu.txt", O_RDWR );
37 
38     if ( -1 == fd1 ) {
39         printf("文件打開失敗\n");
40         perror( "open" );
41         return -1;
42     }else {
43         printf("文件打開成功,fd2=%d\n", fd1);
44     }
45 
46     count2 = write( fd2, buf2, strlen( buf2 ) );
47     if ( -1 == count2 ) {
48         printf( "文件寫入失敗\n" );
49         perror( "write" );
50     }else {
51         printf( "文件寫入成功,寫入的內容是%s\n", buf2 );
52     }
53 
54     close( fd1 );
55     close( fd2 );
56 
57     return 0;
58 }
View Code

 

上面代碼保持不變,再寫入的時候加入flag標志:

fd1 = open( "ghostwu.txt", O_RDWR | O_APPEND );

fd2 = open( "ghostwu.txt", O_RDWR | O_APPEND );

三、 dup后的fd和原來打開文件的fd指向的是同一個文件,同時對這個文件寫入時,是接着寫

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd1 = -1;
11     int fd2 = -1;
12 
13     fd1 = open( "ghostwu.txt", O_RDWR );
14 
15     if ( -1 == fd1 ) {
16         perror( "open" );
17         return -1;
18     }else {
19         printf("文件打開成功:fd=%d\n", fd1);
20     }
21 
22     //dup后的文件,同時write 是接着寫入
23     fd2 = dup( fd1 );
24     printf("文件dup成功:fd=%d\n", fd2);
25 
26     //分別向fd1和fd2指向的文件寫入
27 
28     char buf1[] = "ghost";
29     char buf2[] = "wu";
30 
31     int count1 = -1, count2 = -1;
32 
33     while ( 1 ) {
34         count1 = write( fd1, buf1, strlen( buf1 ) );
35         if ( -1 == count1 ) {
36             perror( "buf1->write" );
37             return -1;
38         }else {
39             printf("buf1->文件寫入成功\n");
40         }
41 
42         sleep( 1 );
43 
44         count2 = write( fd2, buf2, strlen( buf2 ) );
45         if ( -1 == count2 ) {
46             perror( "buf2->write" );
47             return -1;
48         }else {
49             printf("buf2->文件寫入成功\n");
50         }
51     }
52 
53     close( fd1 );
54     close( fd2 );
55     return 0;
56 }
View Code

 

在linux系統中,內核占用了0、1、2這三個fd,當我們運行一個程序得到一個進程時,內部就默認已經打開了3個文件,

對應的fd就是0、1、2。分別叫stdin、stdout、stderr。也就是標准輸入、標准輸出、標准錯誤。接下來,我們把標准輸出關閉,printf就不會輸出,如果用dup復制原來的fd,那么新dup出來的fd就是1(對應標准輸出)

之后標准輸出的內容都會被寫入到原來fd對應的那個文件

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1;
11 
12     fd = open( "ghostwu2.txt", O_RDWR );
13     if ( -1 == fd ) {
14         perror( "open" );
15         return -1;
16     }else {
17         printf( "文件打開成功fd=%d\n", fd );
18     }
19 
20     //fd=0 對應stdin  fd=1 對應 stdout  fd=2 對應stderror
21     close( 1 ); //關閉fd=1的標准輸出之后,printf輸出看不見
22 
23     int newFd = -1;
24 
25     newFd = dup( fd ); //newFd一定是1, 因為分配后的fd從最小的沒被占用的開始
26     char buf[3];
27     sprintf( buf, "%d", newFd ); //newFd轉字符串型
28     printf( "這是一段輸出,由於newFd和fd關聯到標准輸出(newFd=1),會被寫入到文件\n" );
29     write( fd, buf, 1 );
30 
31     return 0;
32 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM