文件操作
(Linux文件操作)) [文件|目錄]
Linux文件操作:為了對(duì)文件和目錄進(jìn)程處理,你需要用到系統(tǒng)調(diào)用(這是 Unix和Linux中與WindowsAPI對(duì)應(yīng)的概念),但系統(tǒng)中同時(shí)還存在一套庫(kù)函數(shù)--標(biāo)準(zhǔn)IO(stdio),可以更有效地進(jìn)行文件處理。
- 文件和設(shè)備
- 系統(tǒng)調(diào)用
- 庫(kù)函數(shù)
- 底層文件訪問
- 管理文件
- 標(biāo)準(zhǔn)I/O庫(kù)
- 格式化輸入和輸出
- 文件和目錄的維護(hù)
- 掃描目錄
- 錯(cuò)誤及其處理
- /proc 文件系統(tǒng)
- 高級(jí)主題:fcntl和mmap
3.1:Linux 文件結(jié)構(gòu)
在Linux中,一切(或者幾乎一切)都是文件,這就意味著,通常程序完全可以像使用文件那樣使用磁盤文件、串行口、打印機(jī)、和其他設(shè)備。
3.1.1 :目錄
文件,除了本身包含內(nèi)容以外,他還會(huì)有一個(gè)名字和一些屬性,即“管理信息”,它包括文件的創(chuàng)建/修改日期和它的訪問權(quán)限。這些屬性被保存在文件的inode(節(jié)點(diǎn))中,他是文件系統(tǒng)中的一個(gè)特殊的數(shù)據(jù)塊,他同時(shí)還包含文件的長(zhǎng)度和文件在磁盤上的存放位置。系統(tǒng)使用的是文件的inode編號(hào),目錄結(jié)構(gòu)為文件命名僅僅是為了便于人們使用。
目錄是用于保存其他文件的節(jié)點(diǎn)號(hào)和名字的文件。目錄文件中的每個(gè)數(shù)據(jù)項(xiàng)都指向某個(gè)文件節(jié)點(diǎn)鏈接,刪除文件名就等于刪除與之對(duì)應(yīng)的連接(文件的節(jié)點(diǎn)號(hào)可以通過ln-i命令查看)。你可以通過使用ln命令在不同的目錄中創(chuàng)建指向同一個(gè)文件的鏈接。
刪除一個(gè)文件時(shí),實(shí)質(zhì)上是刪除了該文件對(duì)應(yīng)的目錄項(xiàng),同時(shí)指向該文件的鏈接數(shù)減1.
3.1.2 :文件和設(shè)備
UNIX和Linux中比較重要的設(shè)備文件有3個(gè):/dev/console 、/dev/tty和/dev/null
- 1./dev/console :這個(gè)設(shè)備代表的是系統(tǒng)控制臺(tái)[錯(cuò)誤信息和診斷信息通常會(huì)發(fā)送到這個(gè)設(shè)備]
- 2./dev/tty :如果一個(gè)進(jìn)程有控制終端的話,那么特殊文件/dev/tty就是這個(gè)控制端(鍵盤和顯示屏,或鍵盤和窗口)的別名(邏輯設(shè)備)。
- 3./dev/null :/dev/null文件是空(null)設(shè)備。
創(chuàng)建空文件的另外一個(gè)方法是使用touch <fileName>命令,該命令的作用是改變文件的修改時(shí)間,如果指定的文件不存在,就創(chuàng)建它,但該命令并不會(huì)把所有的內(nèi)容的文件變成空文件
/dev目錄中的其他設(shè)備包括:硬盤和軟盤、通信端口、磁帶驅(qū)動(dòng)器、CD-ROM、聲卡以及一些代表系統(tǒng)內(nèi)部工作狀態(tài)的設(shè)備。
3.2 系統(tǒng)調(diào)用和設(shè)備驅(qū)動(dòng)程序
操作系統(tǒng)的核心部分,即內(nèi)核,是一組設(shè)備驅(qū)動(dòng)程序。它們是一組對(duì)系統(tǒng)硬件進(jìn)行控制的底層接口。
下面是用于訪問設(shè)備驅(qū)動(dòng)程序的底層函數(shù)(系統(tǒng)調(diào)用)。
- open:打開文件或設(shè)備
- read:從打開的文件或設(shè)備里讀取數(shù)據(jù)
- write:向文件或設(shè)備寫數(shù)據(jù)
- close:關(guān)閉文件或設(shè)備。
- ioctl:把控制信息傳遞給設(shè)備驅(qū)動(dòng)程序。
此外,每個(gè)驅(qū)動(dòng)程序都定義了它自己的一組ioctl命令
3.3 庫(kù)函數(shù)
使用系統(tǒng)調(diào)用會(huì)影響系統(tǒng)的性能。
硬件會(huì)限制對(duì)底層系統(tǒng)調(diào)用一次所讀寫的數(shù)據(jù)塊大小。
3.4 底層文件訪問
每個(gè)運(yùn)行中的程序稱為進(jìn)程(process),它有一些與之關(guān)聯(lián)的文件描述符。
- 0 :標(biāo)準(zhǔn)輸入
- 1 :標(biāo)準(zhǔn)輸出
- 2 :標(biāo)準(zhǔn)錯(cuò)誤
3.4.1 write系統(tǒng)調(diào)用
系統(tǒng)調(diào)用write的作用是吧緩沖區(qū)的buf的前nbytes個(gè)字節(jié)寫入與文件描述符fileds關(guān)聯(lián)的文件中。它返回實(shí)際寫入的字節(jié)數(shù)。
write系統(tǒng)調(diào)用原型:
#include <unistd.h>
size_t write(int filds,const void *buf,size_t nbytes);
3.4.2 read系統(tǒng)調(diào)用
系統(tǒng)調(diào)用read的作用是:從與文件描述符fildes相關(guān)的文件里讀入nbytes個(gè)字節(jié)的數(shù)據(jù),并把它們放到數(shù)據(jù)區(qū)buf中。它返回實(shí)際讀入的字節(jié)數(shù),這可能會(huì)小于請(qǐng)求的字節(jié)數(shù)。
#include <unistd.h>
size_t read(int fildes,void *buf,size_t nbytes);
3.4.3 open系統(tǒng)調(diào)用
為了創(chuàng)建一個(gè)新的描述符,你需要使用系統(tǒng)調(diào)用open
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *path,int oflags);
int open(const char *path,int oflags,mode_t mode);
嚴(yán)格來(lái)說(shuō),在遵循POSIX規(guī)范系統(tǒng)上,使用open系統(tǒng)調(diào)用并不需要包括頭文件sys/types.h和sys/stat.h,但在某些unix系統(tǒng)上,它們可能是必不可少的。
open 建立一條文件和設(shè)備的訪問路徑。成功則返回一個(gè)唯一描述符,供read 和 write調(diào)用,文件描述符石不能進(jìn)行進(jìn)程共享。
oflags : 模式
模式 | 說(shuō)明 |
---|---|
O_RDONLY | 以只讀方式打開 |
O_WRONLY | 以只寫的方式打開 |
O_RDWR | 以讀寫的方式打開 |
open調(diào)用還可以在oflags參數(shù)中包括下列可選模式的組合(按位或)
- O_APPEND :把寫入數(shù)據(jù)追加在文件的末尾
- O_TRUNC: 把文件長(zhǎng)度設(shè)置為零,丟棄已有的內(nèi)容
- O_CREAT:如果需要,就按參數(shù)mode中給出的訪問模式創(chuàng)建文件
- O_EXCL:與O_CREAT一起使用,確保調(diào)用者創(chuàng)建出文件。open調(diào)用是一個(gè)原子操作,也就是說(shuō),它只執(zhí)行一個(gè)函數(shù)調(diào)用。使用這個(gè)可選模式可以防止兩個(gè)程序同時(shí)創(chuàng)建同一個(gè)文件。如果文件已經(jīng)存在,open 調(diào)用將失敗。
POSIX 規(guī)范還標(biāo)準(zhǔn)化了一個(gè)creat調(diào)用,但它并不常用。
3.4.4 訪問權(quán)限的初始值
當(dāng)你使用帶有O_CREAT 標(biāo)志的open 調(diào)用來(lái)創(chuàng)建文件時(shí),你必須使用有3個(gè)參數(shù)格式的open調(diào)用。第三個(gè)參數(shù)mode 時(shí)幾個(gè)標(biāo)志按位或后得到的,這些標(biāo)志在頭文件sys/stat.h中定義。
- S_IRUSR :讀權(quán)限,文件屬主。
- S_IWUSR :寫權(quán)限,文件屬主。
- S_IXUSR :執(zhí)行權(quán)限,文件屬主
- S_IRGRP :讀權(quán)限,文件所屬組
- S_IWGRP :寫權(quán)限,文件所屬組
- S_IXGRP :執(zhí)行權(quán)限,文件所屬組
- S_IROTH :讀權(quán)限,其他用戶
- S_IWOTH :寫權(quán)限,其他用戶
- S_IXOTH :執(zhí)行權(quán)限,其他用戶
請(qǐng)看下面的例子:
open ("myfile",OCREAT,S_IRUSR|S_IXOTH);
1.umask
umask 是一個(gè)系統(tǒng)變量,他的作用是,當(dāng)文件被創(chuàng)建時(shí),為文件的訪問權(quán)限設(shè)定一個(gè)掩碼。執(zhí)行umask命令可以修改這個(gè)變量的值。
2.close 系統(tǒng)調(diào)用
你可以使用close調(diào)用終止文件描述符fildes與其對(duì)應(yīng)文件之間的關(guān)聯(lián)。文件描述符被釋放并能夠重新使用。close 調(diào)用成功時(shí)返回0,出錯(cuò)時(shí)返回-1
注意,檢查close 調(diào)用的返回結(jié)果非常重要。有的文件系統(tǒng),特別是網(wǎng)絡(luò)文件系統(tǒng)可能不會(huì)再關(guān)閉文件之前報(bào)告文件寫操作中的錯(cuò)誤,這是因?yàn)樵趫?zhí)行寫操作時(shí),數(shù)據(jù)可能未被確認(rèn)寫入。
3.ioctl系統(tǒng)調(diào)用
ioctl 調(diào)用有點(diǎn)像是個(gè)大雜燴。它提供了一個(gè)用于控制設(shè)備及其描述符行為和配置底層服務(wù)接口。
#include unistd.h
int ioctl(int fildes,int cmd,...)
--》程序塊一
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
define IN_FILE "in_file.txt"
define OUT_FILE "out_file.txt"
int main(void) {
char buf[1024];
char c;
int in ,out;
int nread;
in = open(IN_FILE,O_RDONLY);
out = open(OUT_FILE,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR);
while(nread = read(in,buf,sizeof(buf)) > 0)
write(out,buf,1);
return EXIT_SUCCESS;
}
3.4.5 其他與文件管理有關(guān)的系統(tǒng)調(diào)用
1:lseek 系統(tǒng)調(diào)用
lseek 系統(tǒng)調(diào)用對(duì)文件描述符fildes的讀寫指針進(jìn)行設(shè)置。也就是說(shuō),你可以用它來(lái)設(shè)置文件的下一個(gè)讀寫位置。讀寫指針既可被設(shè)置為文件中的某個(gè)絕對(duì)位置,也可以把它設(shè)置為相對(duì)于當(dāng)前位置或文件尾的某個(gè)相對(duì)位置
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes,off_t offset, int whence);
off_set參數(shù)用來(lái)指定位置,而whence參數(shù)定義該偏移植的用法。whence可以取值之一:
- SEEK_SET:offset 是一個(gè)絕對(duì)位置。
- SEEK_CUR:offset 是相對(duì)于當(dāng)前位置的一個(gè)相對(duì)位置
- SEEK_END:offset 是相對(duì)于文件尾的一個(gè)相對(duì)位置
lseek 返回從文件頭到文件指針被設(shè)置處的字節(jié)偏移值,失敗時(shí),返回1
2:fstat、stat和lstat系統(tǒng)調(diào)用
fstat 系統(tǒng)調(diào)用返回與打開文件描述符的相關(guān)的文件狀態(tài)信息,該信息將會(huì)寫到一個(gè)buf結(jié)構(gòu)中,buf的地址一參數(shù)形式傳遞給fstat。
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int fstat(int fildes,struct stat *buf)
int stat(const char *path,struct stat *buf)
int lstat(const char *path,struct stat *buf)
0)
3:dup和dup2系統(tǒng)調(diào)用[可用于斷點(diǎn)續(xù)傳]
dup系統(tǒng)調(diào)用提供了一種復(fù)制文件描述符的方法,使我們能夠通過兩個(gè)或者更多個(gè)不同的描述符訪問同一個(gè)文件。這可以用于在文件的不同位置對(duì)數(shù)據(jù)進(jìn)行讀寫。dup系統(tǒng)調(diào)用復(fù)制文件描述符fileds,返回一個(gè)新的描述符。dup2系統(tǒng)調(diào)用則是通過明確指向目標(biāo)描述符來(lái)吧一個(gè)文件描述符復(fù)制為另外一個(gè)。
#include <unistd.h>
int dup(int fildes);
int dup2(int fildes,int fildes2);
當(dāng)你通過管道多個(gè)進(jìn)程間進(jìn)行通信時(shí),這些調(diào)用也很有用。
3.5 標(biāo)準(zhǔn)I/O 庫(kù)
標(biāo)準(zhǔn)I/O庫(kù)(stdio)即其頭文件stdio.h 為底層I/O系統(tǒng)調(diào)用提供了一個(gè)通用的接口。
在標(biāo)準(zhǔn)I/O庫(kù)中,與底層文件描述符對(duì)應(yīng)的是流(stream),它被實(shí)現(xiàn)為指向結(jié)構(gòu)FILE的指針。
標(biāo)準(zhǔn)I/O庫(kù)中的下列庫(kù)函數(shù):
- fopen 、fclose
- fread 、fwrite
- fflush-
- fseek-
- fgetc、getc、getchar
- fputc、putc、putchar
- fgets、gets
- printf、fprintf和sprintf
- scanf、fscanf和sscanf
3.5.1 fopen 函數(shù)
fopen 庫(kù)函數(shù)類似于底層的open系統(tǒng)調(diào)用。它主要用于文件和終端的輸入輸出。
該函數(shù)原型如下:
#include <stdio.h>
FILE *fopen(const char *filename,const char *mode)
fopen 打開由filename參數(shù)指定的文件,并把它與一個(gè)文件流關(guān)聯(lián)起來(lái),mode參數(shù)指定文件的打開方式,它取下列字符串中的值。
- "r" 和 “rb”:以只讀方式打開
- "w" 和 “wb”:以寫方式打開,并把文件長(zhǎng)度截短為0
- "a" 和 “ab”:以寫方式打開,新內(nèi)容追加在文件尾
- "r+" 和 “rb+”或"r+b":以更新方式打開(讀和寫)
- "w+" 和 “wb+”或"w+b":以更新方式打開,并把文件長(zhǎng)度截短為零
- "a+" 和 “ab+”或"a+b":以更新方式打開,新內(nèi)容追加在文件尾
字母b表示文件是一個(gè)二機(jī)制文件而不是文本文件。
fopen 在成功時(shí)返回一個(gè)非空的FILE *指針,失敗時(shí)返回NULL值,NULL值在頭文件stdio.h里定義。
3.5.2 fread 函數(shù)
fread 庫(kù)函數(shù)用于從一個(gè)文件流里讀取數(shù)據(jù)。數(shù)據(jù)從文件流stream讀到ptr指向的數(shù)據(jù)緩沖區(qū)里。
#include <stdio.h>
size_t fread(
void *ptr//
,size_t size//指定每個(gè)數(shù)據(jù)記錄的長(zhǎng)度
,size_t nitems// 給出要傳輸?shù)挠涗泜€(gè)數(shù)
,FILE * stream
);
對(duì)所有向緩沖區(qū)里寫數(shù)據(jù)的標(biāo)準(zhǔn)I/O 函數(shù)來(lái)說(shuō),為數(shù)據(jù)分配空間和檢查錯(cuò)誤是程序員的責(zé)任。
3.5.3 fwrite 函數(shù)
fwrite庫(kù)函數(shù)與fread相似接口。從指定的數(shù)據(jù)緩沖區(qū)里取出數(shù)據(jù)記錄,并把它們寫出輸出流中。它的返回值是成功寫入的記錄個(gè)數(shù)。
#include <stdio.h>
size_t fwrite(const void *ptr,size_t size,size_t nitems,FILE *stream);
請(qǐng)注意,我們不推薦把fread 和fwrite用于結(jié)構(gòu)化數(shù)據(jù)。部分原因在于用fwrite寫的文件在不同的計(jì)算機(jī)體現(xiàn)結(jié)構(gòu)之間可能不具備可移植性
3.5.4 fclose函數(shù)
fclose 庫(kù)函數(shù)關(guān)閉指定的文件stream ,使所有尚未寫出數(shù)據(jù)都寫出。
因?yàn)閟tdio 庫(kù)會(huì)對(duì)數(shù)據(jù)進(jìn)行緩沖,所以使用fcolse是很重要的。
#include stdio.h
int fclose(FILE *stream);
3.5.5 fflush 函數(shù)
fflush 庫(kù)函數(shù)的作用是把文件流離的所有未寫出數(shù)據(jù)立刻寫出。
注意,調(diào)用fclose函數(shù)隱含執(zhí)行了i 次flush操作,所以你不必再調(diào)用fclose之前調(diào)用fflush
#include stdio.h
int fflush(FILE *stream);
3.5.6 fseek函數(shù)
fseek 函數(shù)是與lseek 系統(tǒng)調(diào)用對(duì)應(yīng)的文件流函數(shù)。它在文件流里為下一次讀寫操作指定位置。
fseek函數(shù) 返回一個(gè)整數(shù):0表示成功,-1表示失敗并設(shè)置errno 指出錯(cuò)誤。
#include stdio.h
int fseek(FILE *stream,long int offset,int whence)
3.5.7 fgetc 、getc 和 getchar函數(shù)
fgetc 函數(shù)從文件流里取出下個(gè)字節(jié)并把他作為一個(gè)字符返回,當(dāng)他到達(dá)文件尾或出現(xiàn)錯(cuò)誤時(shí),它返回EOF。你必須通過ferror或 feof 來(lái)區(qū)分者兩種情況。
#include stdio.h
int fgetc(FILE *stream)
int getc(FILE *stream)
int getchar();
3.5.8 fputc、putc 和 putchar函數(shù)
fputc 函數(shù)把一個(gè)字符寫到一個(gè)輸出文件流中。它返回寫入的值,如果失敗,則返回EOF。
#include stdio.h
int fputc(int c,FILE *stream)
int fputc(int c,FILE *stream)
int putchar(int c);
3.5.9 fgets 和 gets 函數(shù)
fgets函數(shù)從輸入文件流stream里讀取一個(gè)字符串。
#include stdio.h
char *fgets(char *s ,int n ,FILE *stream)
char *gets(char *s);
fget把讀到字符寫到s執(zhí)行的字符串里,知道出現(xiàn)下面某種情況:遇到換行符,已經(jīng)傳輸了n-1個(gè)字符或者是達(dá)到文件尾。
當(dāng)成功完成時(shí),fgets返回一個(gè)指向字符串s的指針。如果文件流已經(jīng)到到達(dá)文件尾,fgets會(huì)設(shè)置這個(gè)文件EOF標(biāo)識(shí)并返回一個(gè)空指針。如果出現(xiàn)讀錯(cuò)誤,fgets返回一個(gè)空指針并設(shè)置errno以指出錯(cuò)誤類型。
3.6 格式化輸入輸出
3.6.1:printf、fprintf和sprintf函數(shù)
printf 系列函數(shù)能夠?qū)Ω鞣N不同類型的參數(shù)進(jìn)程格式編排和輸出
#include <stdio.h>
int printf(const char *format,...);
int sprintf(char *s ,const char *format,...);
int fprintf(FILE *stream,const char *format,...);
說(shuō)明:
- printf()函數(shù)把自己的輸出送到標(biāo)準(zhǔn)輸出。
- fprintf()函數(shù)把自己的輸出送到一個(gè)指定的文件流;
- sprintf()函數(shù)把自己的輸出和一個(gè)結(jié)尾空字符寫到座位參數(shù)傳遞過來(lái)的字符串s里。
下面一些常用的轉(zhuǎn)換控制符:
- %d , %i :以十進(jìn)制格式輸出一個(gè)整數(shù)。
- %o , %x :以八進(jìn)制或十六進(jìn)制格式輸出一個(gè)整數(shù)。
- %c : 輸出一個(gè)字符
- %s : 輸出一個(gè)字符串
- %f : 輸出一個(gè)(單精度)浮點(diǎn)數(shù)。
- %e : 以科學(xué)計(jì)數(shù)法格式輸出一個(gè)雙精度浮點(diǎn)數(shù)。
- %g : 以通用格式輸出一個(gè)雙精度浮點(diǎn)數(shù)。
3.6.2:scanf 、fscanf 和 sscanf 函數(shù)
#include stdio.h
int scanf(const char *format,...);
int fscanf(FILE *stream,const char *format);
int sscanf(const char *s,const char *format);
說(shuō)明:
- scanf 函數(shù)讀入的值將保持到對(duì)飲的變量里去,這個(gè)變量類型必須正確,并且它們必須精確匹配格式字符串。
一般來(lái)說(shuō),對(duì)scanf 系列函數(shù)的評(píng)價(jià)并不高,這主要有下面3方面的原因。
- 從歷史來(lái)看,它們的具體實(shí)現(xiàn)都有漏洞
- 它們使用不夠靈活
- 使用它們編寫的代碼不容易看出究竟正在解析什么。
3.6.3:其他流函數(shù)
- fgetpos:獲取文件流的當(dāng)前(讀寫)位置
- fsetpos:設(shè)置文件流的當(dāng)前(讀寫)位置
- ftell:返回文件流當(dāng)前(讀寫)位置的偏移植。
- rewind:重置文件流離的讀寫位置
- freopen:重新使用一個(gè)文件流
- setvbuf:設(shè)置文件流的緩沖機(jī)制
- remove:相當(dāng)于unlink函數(shù),但如果他的path參數(shù)是一個(gè)目錄的話,其作用就相當(dāng)于rmdir函數(shù)
3.6.4:文件流錯(cuò)誤
為了表明錯(cuò)誤,許多stdio苦函數(shù)會(huì)返回一個(gè)超出范圍的值,比如空指針或EOF常熟。此時(shí),錯(cuò)誤由外部變量errno指出:
#include <errno.h>
extern int errno;
注意許多函數(shù)都可能改變errno的值,他的值只有在函數(shù)調(diào)用失敗時(shí)才有意義,你必須在函數(shù)表明失敗之后立即對(duì)其進(jìn)行檢查,你應(yīng)該總是在使用它之前將他先復(fù)制到另一個(gè)變量中,因?yàn)橄駀printf這樣的輸出函數(shù)本身就可能改變errno的值。
你也可以通過檢查文件流的狀態(tài)來(lái)確定是否發(fā)生了錯(cuò)誤,或者是否達(dá)到了文件尾。
#include stdio.h
int ferror(FILE *stream)
int feof(FILE *stream)
void clearerr(FILE *stream)
ferror函數(shù)測(cè)試一個(gè)文件流的錯(cuò)誤標(biāo)識(shí),如果改標(biāo)識(shí)被設(shè)置就返回一個(gè)非零值,否則返回零
feof 函數(shù)測(cè)試一個(gè)文件流的文件尾標(biāo)識(shí)被設(shè)置就返回非零值,否則返回零
clearerr 函數(shù)的作用時(shí)清除由stream指向的文件尾標(biāo)識(shí)和錯(cuò)誤標(biāo)識(shí)。
3.6.5 文件流和文件描述符
每個(gè)文件流都和一個(gè)底層文件描述符相關(guān)聯(lián)。
#include stdio.h
int fileno(FILE *stream)
FILE *fdopen(int fildes,const char *mode);
說(shuō)明:
fileno 函數(shù)來(lái)確定文件流使用的是那個(gè)底層文件描述符
fdopen函數(shù)操作方式與fopen函數(shù)是一樣的,只是前者參數(shù)不是一個(gè)文件名,而是一個(gè)底層文件描述符。
3.7文件和目錄的維護(hù)
3.7.1 chmod 系統(tǒng)調(diào)用
你可以通過chmod 系統(tǒng)調(diào)用來(lái)改變文件或目錄的訪問權(quán)限。
該函數(shù)原型如下:
#include <sys/stat.h>
int chmod(const char *path,mode_t mode);
path參數(shù)指定的文件被修改為具有mode參數(shù)給出的訪問權(quán)限。
參數(shù)mode的定義與open系統(tǒng)調(diào)用中的一樣
3.7.2 chown 系統(tǒng)調(diào)用
“超級(jí)用戶“可以使用chown 系統(tǒng)調(diào)用來(lái)改變一個(gè)文件的屬主。
#include <sys/types.h>
#include <unistd.h>
int chown (const char *path,uid_t owner,gid_t group);
這個(gè)調(diào)用使用的是用戶ID和組ID的數(shù)字值(通過getuid和getgid調(diào)用獲得)和一個(gè)限定誰(shuí)可以修改文件屬主de系統(tǒng)值。
3.7.3 unlink、 link 、 symlink系統(tǒng)調(diào)用
#include unistd.h
int unlink(const char *path);
int link(const char *path1,const char *path2);
int symlink(const char *path1,const char *path);
unlink 系統(tǒng)調(diào)用刪除一個(gè)文件的目錄項(xiàng)并且減少它的連接數(shù)。它在成功時(shí)返回0,失敗時(shí)返回-1
link 系統(tǒng)調(diào)用將創(chuàng)建一個(gè)指向已有文件path1的新鏈接。新目錄項(xiàng)由path2給出。
symlink 系統(tǒng)調(diào)用類似的方式創(chuàng)建符號(hào)鏈接。
3.7.2 mkdir 和rmdir系統(tǒng)調(diào)用
使用mkdir 和 rmdir 系統(tǒng)函數(shù)來(lái)建立和刪除目錄。
#include sys/types.h
#include sys/stat.h
/**
* mkdir系統(tǒng)調(diào)用用于創(chuàng)建目錄,它相當(dāng)于mkdir程序。mkdir調(diào)用將參數(shù)path 作為新建目錄的名字
* 目錄的權(quán)限由參數(shù)mode設(shè)定,
*/
int mkdir (const char *path,mode_t mode);
/**
* rmdir 系統(tǒng)調(diào)用用于刪除目錄,但只有在目錄為空時(shí)才行。
*/
int rmdir (const char *path)
3.7.5 chdir 系統(tǒng)調(diào)用和getcwd函數(shù)
程序可以通過chdir系統(tǒng)調(diào)用來(lái)切換目錄
程序可以通過調(diào)用getcwd函數(shù)來(lái)確定自己的當(dāng)前工作目錄
#include unistd.h
int chdir(const char *path)
int getcwd (char *buf,size_t size)
getcwd 函數(shù)把當(dāng)前目錄的名字寫到給定的緩沖區(qū)buf里。如果目錄名的長(zhǎng)度超出了參數(shù)size給出的緩沖區(qū)長(zhǎng)度(一個(gè)ERANGE錯(cuò)誤),他就返回NULL,如果成功,它返回指針buf
如果再程序運(yùn)行過程中,目錄被刪除(EINVAL錯(cuò)誤)或者有關(guān)權(quán)限發(fā)生變化(EACCESS)錯(cuò)誤,gecwt也可能返回NULL
3.8 掃描目錄
Linux 系統(tǒng)上一個(gè)常見的問題就是掃描目錄,也就是確定一個(gè)特定目錄下存放的文件。
與目錄相關(guān)的函數(shù)dirent.h頭文件聲明。
函數(shù)列表:
- opendir、closedir
- readdir
- telldir
- seekdir
- closedir
3.8.1 opendir 函數(shù)
opendir函數(shù)作用是打開一個(gè)目錄并建立一個(gè)目錄流。如果成功,它返回一個(gè)指向dir結(jié)構(gòu)的指針,該指針用于讀取目錄數(shù)據(jù)項(xiàng)
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
opendir在失敗時(shí)返回一個(gè)空指針。注意,目錄流使用一個(gè)底層文件描述符來(lái)訪問目錄本身,所以如果打開的文件過多,opendir可能會(huì)失敗
3.8.2 readdir 函數(shù)
readdir 函數(shù)返回一個(gè)指針,該指針指向的結(jié)構(gòu)里保存著目錄流dirp中下一個(gè)目錄項(xiàng)的有關(guān)資料。
#include <sys/types.h>
#include <dirent>
struct dirent *readdir(DIR *dirp);
注意:如果在readdir函數(shù)掃描目錄的同時(shí)還有其他進(jìn)程在該目錄里創(chuàng)建或刪除文件,readdir將不保證能夠列出該墓里的所有文件(和子目錄)
dirent結(jié)構(gòu)中包含的目錄項(xiàng)內(nèi)容包括以下部分。
ino_t d_ino:文件的inode節(jié)點(diǎn)號(hào)
char d_name[]文件名字。
3.8.3 telldir函數(shù)
telldir函數(shù)的返回值紀(jì)錄著一個(gè)目錄流里的當(dāng)前位置。
#include <sys/types.h>
#include <dirent.h>
long int telldir(DIR *dirp)
3.8.4: seekdir 函數(shù)
seekdir函數(shù)作用就是設(shè)置目錄流dirp的目錄項(xiàng)指針。loc的值用來(lái)設(shè)置指針位置,他應(yīng)該通過前個(gè)telldir調(diào)用獲得。
#include <sys/types.h>
#include <dirent.h>
void seekdir(DIR *dirp,long int loc);
3.8.5: closedir 函數(shù)
closedir 函數(shù)關(guān)閉一個(gè)目錄流并釋放與之關(guān)聯(lián)的資源,他的執(zhí)行成功返回0,發(fā)生錯(cuò)誤時(shí)返回-1
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp)
總結(jié)案例
/*
============================================================================
Name : printdir.c
Author : james
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
void printdir(char *dir ,int depth){
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL){
fprintf(stderr,"cannot open directory:%s\n",dir);
return ;
}
chdir(dir);
while((entry == readdir(dp)) != NULL){
lstat (entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)){
/* Found a directory ,but ignore. and..*/
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
printf("%*%s\n",depth,"",entry->d_name);
printdir(entry->d_name,depth+4);
}
else printf("%*%s%s\n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
int main(void) {
printf("Directory scan of /home/james/workspace:\n");
printdir("/home/james/workspace",0);
printf("done.\n");
return EXIT_SUCCESS;
}
3.9 錯(cuò)誤處理
錯(cuò)誤代碼的取值喝含義都列在頭文件errno.h里:
- ERERM 操作不允許
- ENOENT 文件或目錄不存在
- EINTR 系統(tǒng)調(diào)度被中斷
- EIO I/O 錯(cuò)誤
- EBUSY 設(shè)備或資源忙
- EEXIST 文件存在
- EINVAL 無(wú)效參數(shù)
- EMFILE 打開文件過多
- ENODEV 設(shè)備不存在
- EISDIR 是一個(gè)目錄
- ENOTDIR 不是一個(gè)目錄
有兩個(gè)非常有用的函數(shù)可以用來(lái)報(bào)告出現(xiàn)的錯(cuò)誤,它們是strerror 和perror
3.9.1 strerror 函數(shù)
strerror 函數(shù)把錯(cuò)誤代碼映射為一個(gè)字符串,該字符串對(duì)發(fā)生的錯(cuò)誤類型進(jìn)程說(shuō)明。這在記錄錯(cuò)誤條件時(shí)十分有用
函數(shù)如下
#include <string.h>
char *strerror(int errnum)
3.9.2 perror 函數(shù)
perror 函數(shù)也罷errno 變量中報(bào)告的當(dāng)前錯(cuò)誤映射到了一個(gè)字符串,并把它輸出到標(biāo)準(zhǔn)錯(cuò)誤輸出流。該字符串的前面加上字符串s(如果不為null)中給出的消息,再加上一個(gè)冒號(hào)和空格
該函數(shù)原型如下:
#include <stdio.h>
void perror(const char *s);
請(qǐng)看下面的栗子:
perror(“program”);
他可能在標(biāo)準(zhǔn)錯(cuò)誤輸出中給出如下輸出結(jié)果:
program:Too many open files
3.10 /proc 文件系統(tǒng)
Linux 提供了一個(gè)特殊的文件系統(tǒng)procfs ,它通常以/proc 目錄的形式呈現(xiàn)。該目錄中包含了許多的特殊文件用來(lái)對(duì)缺懂程序和內(nèi)河星系進(jìn)程更高層的訪問。只要應(yīng)用程序有正確的訪問權(quán)限,他們就可以通過讀寫這些文件來(lái)獲得信息或設(shè)置參數(shù)。
3.11 高級(jí)主題:fcntl 和 mmap
3.11.1: fcntl 系統(tǒng)調(diào)用
fcntl 系統(tǒng)調(diào)用對(duì)底層文件描述符提供了更多的操縱方法。
#include <fcntl.h>
int fcntl(int fildes,int cmd)
int fcntl(int fildes,int cmd ,long arg)
利用fcntl系統(tǒng)調(diào)用,你可以對(duì)伐開的文件描述符進(jìn)行各種操作,報(bào)考對(duì)它們進(jìn)程復(fù)制、獲取和設(shè)置文件描述符的標(biāo)志,以及管理建設(shè)性文件性文件鎖等。
3.11.2 mmap 函數(shù)
Unix 提供了一個(gè)有用的功能以允許程序共享內(nèi)存,Linux內(nèi)核從2.0版本開始已經(jīng)把這一功能包括進(jìn)程。mmap(內(nèi)存映射)函數(shù)作用是建立一段可被兩個(gè)或多個(gè)程序讀寫內(nèi)存。一個(gè)程序?qū)λ鞒龅男薷目梢员黄渌绦蚩匆姟?/p>
這一組功能還可以用到文件處理上。你可以是某個(gè)磁盤文件的全部看起來(lái)就像在內(nèi)存中的一個(gè)數(shù)組,如果文件由紀(jì)錄組成,而這些記錄又能夠用C語(yǔ)言中的結(jié)構(gòu)來(lái)描述的話,就可以通過訪問結(jié)構(gòu)數(shù)組來(lái)更新文件的內(nèi)容了。
mmap函數(shù)創(chuàng)建了一個(gè)指向一段內(nèi)存區(qū)域的指針,該內(nèi)存區(qū)域可以通過一個(gè)打開的文件描述符訪問文件的內(nèi)容相關(guān)聯(lián)。
#include <sys/mman.h>
void *mmap(void *addr ,size_t len, int port,int flags,int fildes,off_t off);
可以通過傳遞off參數(shù)來(lái)改變共享內(nèi)存段訪問文件中暑的啟示偏移值。打開文件描述符由filds參數(shù)給出。可以訪問的數(shù)據(jù)量(即內(nèi)存的長(zhǎng)度)由len參數(shù)設(shè)置。
port 參數(shù)用于設(shè)置內(nèi)存段的訪問權(quán)限。
- PROT_READ:允許讀該內(nèi)存段
- PROT_WRITE:允許寫該內(nèi)存段
- PROT_EXEC:允許執(zhí)行該內(nèi)存段
- PROT_NONE:該內(nèi)存段不能被訪問
flags參數(shù)控制程序?qū)υ搩?nèi)存段的改變所造成的影響。
- MAP_PRIVATE 內(nèi)存段時(shí)私有的,對(duì)它的修改只對(duì)本進(jìn)程有效
- MAP_SHARED 把該內(nèi)存段的修改保存到磁盤文件中
- MAP_FIXED 該內(nèi)存段必須位于addr指定的地址處
msync 函數(shù)的作用是:把該內(nèi)存段的某個(gè)部分或爭(zhēng)端中的修改回到被映射的文件中(或者從被映射文件里讀出)。
mumap 函數(shù)的作用是:釋放內(nèi)存段