今天開始學習unix/linux系統下的文件I/O函數—打開文件、讀文件、寫文件等。大多數文件I/O只需要用到5個函數:open,read,write,lseek已經close,這5個函數都直接調用同名的系統調用,所以是不帶緩沖的,本節,主要介紹open和creat函數。
1.open函數
1)函數原型:
#include <fcntl.h>
int open(const char* pathname,int flags)
int open(const char* pathname,int flags,mode_t mode);
2)函數功能:
打開或建立一個文件。對於open函數,僅當創建文件時,才用到第三個參數
3)參數說明:
pathname:打開或創建的文件名
flags:用下列一個或多個常量進行“或”運算構成flags參數(這些常量定義在<fcntl.h>
O_RDONLY 只讀打開
O_WRONLY 只寫打開
O_RDWR 讀寫打開
以上三個常量只能選一個,下面的則可以多選:
O_APPEND 每次寫時都追加到文件的尾端。
O_CREAT 若此文件不存在,則創建它。使用此選項時,需要第三個參數mode,用其
指定新文件的訪問權限。
O_EXCL 如果同時制定了O_CREAT,而文件已經存在,則會報錯。因此可以測試一個
文件是否存在,如果不存在,則創建此文件,這使測試和創建兩者成為一個
原子操作。
O_TRUNC 如果此文件存在,而且為只讀或讀寫成功打開,則將其長度截短為0。
O_NOCTTY 如果pathname指的是終端設備,則不將該設備分配作為此進程的控制終端。
O_NONBLOCK 如果pathname指的是一個FIFO、一個塊特殊文件或一個字符特殊文件,
則此選項為文件的本次打開操作和后續的I/O操作設置非阻塞模式。
mode:用下列一個或多個常量進行“或”運算構成mode參數(這些常量定義在sys/stat.h)
S_IRWXU:00700 擁有者讀寫執行權限
S_IRUSR: 00400 擁有者讀權限
S_IWUSR:00200 擁有者寫權限
S_IXUSR: 00100 擁有者執行權限
S_IRWXG:00070 組內成員讀寫執行權限
S_IRGRP: 00040 組內成員讀權限
S_IWGRP:00020 組內成員寫權限
S_IXGRP: 00010 組內成員執行權限
S_IRWXO:00007 其他成員讀寫執行權限
S_IROTH: 00004 其他成員讀權限
S_IWOTH:00002 其他成員寫權限
S_IXOTH: 00001 其他成員執行權限
也可以直接指定mode的值,如0777,0541等
注意:此處設定的mode的值並不是文件最終的權限,文件最終的權限是按照mode & ~umask得到的,而默認的umask是0022,所以如果想按照mode的值設置文件權限,需要在建立文件之前將umask的值設置為0000
4)實例程序:
以下程序當不存在test.txt時創建一個test.txt文件,並給予最大權限
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> int main() { int fd; umask(0000); //if((fd = open("test.txt",O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,0777)) == -1) if((fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,S_IRWXU | S_IRWXG | S_IRWXO)) == -1) { //printf("open:%s with errno:%d\n",strerror(errno),errno); perror("open"); perror(“open”); exit(1); } else { printf("success"); } close(fd); return 0; }
執行結果:
[hb@localhost unixadvance]$ gcc -g -o testOpen testOpen.c
[hb@localhost unixadvance]$ ./testOpen
success
[hb@localhost unixadvance]$ ls -al
總計 76
drwxrwxr-x 2 hb hb 4096 08-02 11:19 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxrwxr-x 1 hb hb 5476 08-02 11:17 a.out
-rw-rw-r-- 1 hb hb 529 08-02 11:03 testCreat.c
-rwxrwxr-x 1 hb hb 6696 08-02 11:19 testOpen
-rw-rw-r-- 1 hb hb 529 08-02 11:17 testOpen.c
-rw-r--r-- 1 root root 12288 08-02 11:17 .testOpen.c.swp
-rwxrwxrwx 1 hb hb 0 08-02 11:19 test.txt
可以看到test.txt的權限確實是777,而如果去掉程序中umask(0000)一句,則創建出來的文件權限為:
[root@localhost unixadvance]# ls -al
總計 76
drwxrwxr-x 2 hb hb 4096 08-02 11:25 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxrwxr-x 1 hb hb 5476 08-02 11:17 a.out
-rw-rw-r-- 1 hb hb 529 08-02 11:03 testCreat.c
-rwxr-xr-x 1 root root 6595 08-02 11:25 testOpen
-rw-rw-r-- 1 hb hb 531 08-02 11:21 testOpen.c
-rw-r--r-- 1 root root 12288 08-02 11:21 .testOpen.c.swp
-rwxr-xr-x 1 root root 0 08-02 11:25 test.txt
這是因為默認的umask是022,所以默認的文件權限就為0755。
當我們第二次執行此程序:
[root@localhost unixadvance]# ./testOpen
open: File exists
File exists這個錯誤是由perror("open")報出來的,它定義在<stdio.h>中
perror (const char *s)用 來 將 上 一 個 函 數 發 生 錯 誤 的 原 因 輸 出 到 標 准 設備 (stderr) 。參數 s 所指的字符串會先打印出,后面再加上錯誤原因字符串。此錯誤原因依照全局變量errno 的值來決定要輸出的字符串。
在庫函數中有個errno變量,每個errno值對應着以字符串表示的錯誤類型。當你調用"某些"函數出錯時,該函數已經重新設置了errno的值。perror函數只是將你輸入的一些信息和現在的errno所對應的錯誤一起輸出。
如果想看到errno的值,則將perror()替換為
printf("open:%s with errno:%d\n",strerror(errno),errno); perror("open");
此時的執行結果為:
[root@localhost unixadvance]# ./testOpen
open:File exists with errno:17
errno定義在<errno.h>中
2.creat函數
1)函數原型:
#include <fcntl.h>
int creat(const char *pathname ,mode_t mode);
2)函數功能:
創建一個新文件。
creat函數等效於如下函數:
open(pathname,O_WRONLY | O_CREAT | O_TRUNC, mode)
注意:creat只能以只寫方式打開,不能讀,讀出的將是亂碼!
3)參數說明:
pathname:創建的文件名
mode:與open的mode相同
4)程序實例:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> int main() { int fd; umask(0000); if((fd = creat("test.txt",0777)) == -1) { //perror("open"); printf("open:%s with errno:%d\n",strerror(errno),errno); exit(1); } else { printf("success\n"); } close(fd); return 0; }
運行結果:
[root@localhost unixadvance]# gcc testCreat.c
[root@localhost unixadvance]# ./a.out
success
[root@localhost unixadvance]# ls -al
總計 76
drwxrwxr-x 2 hb hb 4096 08-02 15:02 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxr-xr-x 1 root root 5462 08-02 15:02 a.out
-rw-rw-r-- 1 hb hb 529 08-02 15:02 testCreat.c
-rw-r--r-- 1 root root 12288 08-02 15:02 .testCreat.c.swp
-rwxr-xr-x 1 root root 6907 08-02 11:39 testOpen
-rw-rw-r-- 1 hb hb 611 08-02 11:39 testOpen.c
-rwxrwxrwx 1 root root 0 08-02 15:02 test.txt
當我們第二次運行程序:
[root@localhost unixadvance]# ./a.out
success
仍然是success,說明creat函數不管原來有沒有同名文件都會返回成功,那是否覆蓋了呢?我們繼續試驗:
在已經生成的test.txt里加入一句話:This is the old one!
然后將原程序中fd = creat("test.txt",0777) 改為 fd = creat("test.txt",0700),結果如下:
[root@localhost unixadvance]# ./a.out
success
[root@localhost unixadvance]# ls -al
總計 76
drwxrwxr-x 2 hb hb 4096 08-02 15:08 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxr-xr-x 1 root root 5462 08-02 15:08 a.out
-rw-rw-r-- 1 hb hb 530 08-02 15:08 testCreat.c
-rw-r--r-- 1 root root 12288 08-02 15:08 .testCreat.c.swp
-rwxr-xr-x 1 root root 6907 08-02 11:39 testOpen
-rw-rw-r-- 1 hb hb 611 08-02 11:39 testOpen.c
-rwxrwxrwx 1 root root 0 08-02 15:08 test.txt
說明:如果創建的文件與現有文件重名,則creat函數會將重名文件內容清零(這其實是由O_TRUNC標志位決定的),但原文件的權限卻不會被改變!!