Linux文件操作與IO

底層文件訪問


open系統(tǒng)調(diào)用

#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);

在遵循POSIX規(guī)范的系統(tǒng)上刑枝,使用open系統(tǒng)調(diào)用并不需要包含頭文件sys/types.h和sys/stat.h藐唠,但在某些UNIX系統(tǒng)上操灿,他們可能必不可少来涨。

open系統(tǒng)調(diào)用建立了一條從到文件或設(shè)備的訪問路徑迅诬,該調(diào)用將得到與該文件相關(guān)聯(lián)的文件描述符(file discriptor)
任何一個進(jìn)程可以同時打開的文件數(shù)目有限形导,通常由limits.h頭文件中的常量OPEN_MAX定義扫茅,該值與系統(tǒng)有關(guān)琐凭,且這個限制本身還受到系統(tǒng)全局性限制影響暂衡,所以一個程序未必總是可以打開這么多文件蓝厌。在Linux系統(tǒng)中,這個限制可以隨著系統(tǒng)運(yùn)行而調(diào)整古徒,所以O(shè)PEN_MAX并不是一個常量拓提。它通常一開始就被設(shè)置未256

參數(shù) 解釋
path 準(zhǔn)備打開的文件或者設(shè)備的名字
oflags 打開文件所采取的動作
mode 文件訪問模式

oflag參數(shù)包括下列值的組合(用“按位與”操作)

解釋
O_APPEND 把寫入數(shù)據(jù)追加到文件末尾
O_TRUNC 把文件長度設(shè)置為0,丟棄已有內(nèi)容
O_CREAT 如需要就按參數(shù)mode給出的訪問模式創(chuàng)建文件
O_EXCL 與O_CREAT一起使用隧膘,確保調(diào)用者創(chuàng)建出文件代态。open調(diào)用是一個原子操作,它只執(zhí)行一個函數(shù)調(diào)用疹吃。使用這個可選模式可以防止兩個程序同時創(chuàng)建一同一個文件蹦疑。如果文件已經(jīng)存在,open調(diào)用失敗

當(dāng)你使用帶有O_CREAT標(biāo)志的open調(diào)用時萨驶,你必須使用帶3個有參數(shù)的open調(diào)用歉摧。第3個參數(shù)mode是幾個標(biāo)志位按位或后得到的,這些標(biāo)志在頭文件sys/stat.h中定義

權(quán)限 擁有者
S_IRUSR r user
S_IWUSR w user
S_IXUSR x user
S_IRGRP r group
S_IWGRP w group
S_IXGRP x group
S_IROTH r other
S_IWOTH w other
S_IXOTH x other

用戶掩碼(由umask命令設(shè)定)會影響被創(chuàng)建文件的訪問權(quán)限open調(diào)用中參數(shù)mode的值與當(dāng)前用戶掩碼的反值做與操作


write系統(tǒng)調(diào)用

#include <stdio.h> 
size_t write(int fd, const void *buf, size_t nbytes);

write系統(tǒng)調(diào)用把緩沖區(qū)buf中的前n個bytes寫入與文件描述符fd相關(guān)的文件中腔呜。

參數(shù) 解釋
fd 數(shù)據(jù)目的地的文件描述符
buf 數(shù)據(jù)來源地的指針
nbytes 寫入數(shù)據(jù)字節(jié)數(shù)

返回實際寫入的字節(jié)數(shù)叁温,返回值可能小于nbytes。如果返回0核畴,表示未寫入數(shù)據(jù)膝但;如果返回-1,表示write調(diào)用出錯谤草,錯誤代碼保存在全局變量errno中跟束。


read系統(tǒng)調(diào)用

 #include <unistd.h> 
 size_t read(int fd, void *buf, size_t nbytes);

read系統(tǒng)調(diào)用從與文件描述符fd相關(guān)聯(lián)的文件中讀入nbytes字節(jié)的數(shù)據(jù),并把它們放到buf中丑孩。

參數(shù) 解釋
fd 數(shù)據(jù)來源文件的文件描述符
buf 數(shù)據(jù)目的地指針
nbytes 讀入數(shù)據(jù)字節(jié)數(shù)

返回實際讀入的字節(jié)數(shù)冀宴,可能會小于nbytes。如果返回0温学,表示未讀入任何數(shù)據(jù)略贮,已到達(dá)文件尾;返回-1表示出現(xiàn)錯誤。


close系統(tǒng)調(diào)用

#include <unistd.h> 
int close(int fd);

close調(diào)用終止文件描述符fd與其對應(yīng)文件之間的關(guān)聯(lián)刨肃。文件描述符被釋放并能夠重新使用古拴。close調(diào)用成功時候返回0,出錯時返回-1真友。
檢查close調(diào)用的返回結(jié)果非常重要黄痪。有的文件系統(tǒng),特別使網(wǎng)絡(luò)文件系統(tǒng)盔然,可能不會在關(guān)閉文件之前報告文件寫操作中出現(xiàn)的錯誤桅打,這是因為在執(zhí)行寫操作時,數(shù)據(jù)可能未被確認(rèn)寫入


lseek系統(tǒng)調(diào)用

#include <unistd.h> 
#include <sys/types.h> 

off_t lseek(int fd, off_t offset, int whence);

lseek系統(tǒng)調(diào)用對文件描述符的讀寫指針位置進(jìn)行設(shè)置> 參數(shù)whence定義該偏移量offset的用法愈案,可取下列值
| 參數(shù) | 解釋 |
| ------------- |:-------------:|
|SEEK_SET|絕對位置|
|SEEK_CUR|相對于當(dāng)前位置|
|SEEK_END|相對于文件尾|


fstat stat lstat系統(tǒng)調(diào)用

#include <unistd.h> 
#include <sys/types.h>
#include <sys/stat.h> 
int fstat(int fd, struct stat *buf);
int stat(const char *path, struct stat *buf); 
int lstat(const char *paht, struct stat *buf);

fstat系列調(diào)用返回與打開的文件描述符相關(guān)聯(lián)的文件的狀態(tài)信息挺尾,該信息將被寫入buf中
stat和lstat返回的使通過文件名查詢到的狀態(tài)信息。它們產(chǎn)生相同效果站绪,但當(dāng)文件是符號鏈接時遭铺,lstat返回的是該符號鏈接本身的信息,而stat返回的使該鏈接指向文件的信息恢准。


標(biāo)準(zhǔn)IO庫

在標(biāo)準(zhǔn)IO庫中魂挂,與底層文件描述符對應(yīng)的流(stream),它被實現(xiàn)為指向結(jié)構(gòu)體FILE的指針(FILE )> 在啟動程序時馁筐,有三個文件流被自動打開的涂召。它們是stdin stdout stderr他們與底層文件描述符0 1 2相對應(yīng),分別代表標(biāo)準(zhǔn)輸入 標(biāo)準(zhǔn)輸出 標(biāo)準(zhǔn)錯誤輸出IO函數(shù)可能存在緩沖區(qū)安全問題敏沉,應(yīng)該避免使用這樣的函數(shù)果正,或者十分謹(jǐn)慎地使用有安全問題的函數(shù)*

fopen函數(shù)

#include <stdio.h> 
FILE *fopen(const char *filename, const char *mode);

fopen打開由參數(shù)filename指定的文件,并把它與一個文件流關(guān)聯(lián)起來盟迟。> > 參數(shù)mode指定文件的打開方式秋泳,取下列字符串中的值。

參數(shù) 解釋
"rb" or "rb" 只讀
"w" or "wb" 寫方式队萤,并把文件長度截短為0 "a" or "ab" 寫方式轮锥,新內(nèi)容追加到文件尾
"r+" or "rb+" 讀寫
"w+" or "wb+" 讀寫,文件長度截短為0
"a+" or "ab+" 讀寫要尔,新內(nèi)容追加在文件尾

字母b表示文件是一個二進(jìn)制(binary)文件fopen調(diào)用成功將會返回一個非空的FILE指針,失敗時返回NULLunix和Linux把所有文件都看成二進(jìn)制文件新娜,參數(shù)mode必須是字符串赵辕,所以總是應(yīng)該使用雙引號,而不是單引號*
可用的文件流數(shù)量也是有限的概龄。實際限制由頭文件stdio.h中的FOPEN_MAX定義还惠,它的值至少為8,在linux系統(tǒng)中通常是16私杜。

fread函數(shù)

#include <stdio.h> 
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

數(shù)據(jù)從文件流stream讀到ptr指向的數(shù)據(jù)緩沖區(qū)中蚕键。fread和fwrite都是對數(shù)據(jù)記錄進(jìn)行操作救欧,size參數(shù)指定每個數(shù)據(jù)記錄的長度,計數(shù)器ntimes給出要傳輸?shù)挠涗泜€數(shù)锣光。
返回值是成功讀到數(shù)據(jù)緩沖區(qū)里的記錄個數(shù)(不是字節(jié)數(shù))笆怠。當(dāng)?shù)竭_(dá)文件尾,它的返回值可能會小于ntimes誊爹,甚至可以是0蹬刷。

fwrite函數(shù)

 #include<stdio.h> 
 size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);

fwrite與fread有相似的接口。它從指定的數(shù)據(jù)緩沖區(qū)取出數(shù)據(jù)記錄频丘,并把它們寫到文件流stream中办成。
返回值是成功寫入的記錄個數(shù)

fclose函數(shù)

#include <stdio.h> 
int fclose(FILE *stream);

fclose函數(shù)關(guān)閉指定的文件流stream,使所有尚未寫出的數(shù)據(jù)寫出搂漠。如果要確保數(shù)據(jù)已經(jīng)全部寫出迂卢,就應(yīng)該調(diào)用fclose函數(shù)。當(dāng)程序正常結(jié)束時桐汤,會自動對所有還打開的文件流調(diào)用fclose函數(shù)冷守。

fflush函數(shù)

#include <stdio.h>
int fflush(FILE *stream);

將文件流里所有尚未寫出的數(shù)據(jù)立刻寫出。有時在調(diào)試程序時惊科,可以用它來確認(rèn)程序正在寫數(shù)據(jù)而不是被掛起了拍摇。調(diào)用fclose函數(shù)隱含執(zhí)行了一次flush操作


fseek函數(shù)

fseek函數(shù)與lseek函數(shù)系統(tǒng)調(diào)用對應(yīng)的文件流函數(shù)。它在文件流里為下次讀寫操作指定位置馆截。offset和whence參數(shù)的含義和取值與前面的lseek系統(tǒng)調(diào)用完全一樣充活。但是fseek返回一個證書:0表示成功,-1表示失敗并設(shè)置errno支出錯誤蜡娶。


fgetc getc getchar函數(shù)

 #include <stdio.h> 
 int fgetc(FILE *stream); 
 int getc(FILE *stream); int getchar();

fgetc函數(shù)從文件流stream取出下一個字節(jié)并把它作為一個字符返回混卵。當(dāng)它到達(dá)文件尾或者出現(xiàn)錯誤時,它返回EOF(end of file)窖张∧凰妫可以通過ferror或者feof來區(qū)分> getc的作用和fgetc相同,但是它有可能被實現(xiàn)為一個宏(macro)宿接,如果這樣赘淮,stream參數(shù)就可能被計算不止一次,所以它不能有副作用睦霎。此外梢卸,不能保證能夠使用getc的地址作為函數(shù)指針

getchar函數(shù)相當(dāng)于getc(stdin),它從標(biāo)準(zhǔn)輸入里讀取下一個字符副女。


fputc putc putchar函數(shù)

 #include<stdio.h> 
 int fputc(int c, FILE *stream);
 int putc(int c, FILE *stream); 
 int putchar(int c);

fputc函數(shù)把字符c寫到文件流stream中蛤高。它返回寫入的值,如果失敗則返回EOF.> putc函數(shù)作用相當(dāng)于fputc,但它可能被實現(xiàn)為一個宏戴陡。
putchar函數(shù)相當(dāng)于putc(c, stdout)塞绿,它把單個字符寫到標(biāo)準(zhǔn)輸出。注意,putchar和getchard都是把字符當(dāng)做int類型而不是插入類型恤批。這就允許文件尾(EOF)取值-1异吻,這是一個超出字符數(shù)字編碼范圍的值。


fgets gets函數(shù)

#include <stdio.h> 
char *fgets(char *s, int n, FILE *stream);  
char *gets(char *s);

fgets函數(shù)把讀到的字符寫到s指向的字符串里开皿,知道出現(xiàn)下列情況:

  1. 遇到換行符
  2. 已經(jīng)傳輸了n-1個字符
  3. 到達(dá)文件尾
    它會把遇到的換行符也傳遞到接收字符串涧黄,再加上一個表示結(jié)尾的空字符\0。
    當(dāng)調(diào)用成功時赋荆,fgets返回一個指向字符串s的指針笋妥。如果文件流已經(jīng)到達(dá)文件尾,fgets會設(shè)置這個文件流的EOF標(biāo)志并返回一個空指針窄潭。如果出現(xiàn)讀錯誤春宣,fgets返回一個空指針并設(shè)置errno。

gets函數(shù)類似于fgets函數(shù)嫉你,但gets函數(shù)存在緩沖區(qū)溢出問題月帝,不推薦使用


格式化輸入和輸出


printf fprintf sprintf snprintf函數(shù)

#include <stdio.h> 
int printf(const char *format, ...); 
int sprintf(char *s, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int snprintf(char *s, size_t size, const char *format, ...);

snprintf修復(fù)了緩沖區(qū)問題,推薦使用

snprintf將可變個參數(shù)(...)按照format格式化成字符串幽污,然后將其復(fù)制到str中(1) 如果格式化后的字符串長度 < size嚷辅,則將此字符串全部復(fù)制到str中,并給其后添加一個字符串結(jié)束符('\0')距误;
(2) 如果格式化后的字符串長度 >= size簸搞,則只將其中的(size-1)個字符復(fù)制到str中,并給其后添加一個字符串結(jié)束符('\0')返回值為欲寫入的字符串長度准潭。

常見格式控制符:

控制符 解釋
%d, %i 十進(jìn)制格式輸出整數(shù)
%o, %x 八進(jìn)制或十六進(jìn)制格式輸出一個整數(shù)
%c 輸出一個字符
%s 輸出字符串
%f 單精度浮點數(shù)
%e 科學(xué)計數(shù)法格式輸出雙精度浮點數(shù)
%g 以通用格式輸出一個雙精度浮點數(shù)

-------#### 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, ...);

scanf系列函數(shù)實現(xiàn)有漏洞趁俊,使用不夠靈活,不推薦使用


錯誤處理

本文中的許多函數(shù)和系統(tǒng)調(diào)用都可能失敗刑然。它們會在失敗時候設(shè)置外部變量errno來指明失敗原因
#include <errno.h>
extern int errno;

你必須在函數(shù)調(diào)用失敗之后立刻對其進(jìn)行檢查寺擂,你總是應(yīng)該在使用它之前將它復(fù)制到另一個變量,因為它的值可能被下一個函數(shù)調(diào)用覆蓋泼掠,即使下一個函數(shù)并沒有出錯怔软,也可能會覆蓋這個變量

錯誤代碼 解釋
EPERM 操作不允許
ENOENT 文件或目錄不存在
EINTR 系統(tǒng)調(diào)用被中斷
EIO IO錯誤
EBUSY 設(shè)備或資源忙碌
EEXIST 文件存在
EINVAL 無效參數(shù)
EMFILE 打開文件過多
ENODEV 設(shè)備不存在
EISDIR 是一個目錄
ENOTDIR 不是一個目錄

以上錯誤代碼均保存在頭文件errno.h中


#include<stdio.h> int ferror(FILE *stream);
int feof(FILE *stream); 
void clearerr(FILE *stream);

ferror函數(shù)測試文件流stream的錯誤標(biāo)識,如果該標(biāo)識被設(shè)置就返回一個非0值武鲁,否則返回0
feof函數(shù)測試一個文件流的文件尾標(biāo)識爽雄,如果該標(biāo)識被設(shè)置就返回非0值,否則返回0沐鼠。
clearerror函數(shù)的作用是清除由stream指向的文件流的文件尾標(biāo)識和錯誤標(biāo)識。它無返回值,也未定義任何錯誤饲梭。


 #include <string.h> char *strerror(int errnum);

strerror函數(shù)把錯誤代碼映射成一個字符串乘盖,該字符串對錯誤代碼進(jìn)行解釋。
#include <stdio.h> void perror(const char *s);

perror函數(shù)把errno變量中的當(dāng)前錯誤映射成一個字符串憔涉,并把它輸出到標(biāo)準(zhǔn)錯誤輸出流(stderr)订框。該字符串的前面加上字符串s(如果不為空),再加上一個冒號和空格兜叨。


void *指針類型

void即“無類型”穿扳,void *則為“無類型指針”,可以指向任何數(shù)據(jù)類型国旷。反之則不然,例如:
void *p;
int *a;
p = a; //合法
a = p; //不合法
a = (int *) p; //合法

如果函數(shù)的參數(shù)可以是任意類型指針矛物,那么應(yīng)聲明其參數(shù)為void*。例如內(nèi)存操作函數(shù):

void * memcpy(void *dest,const void *src,size_t len);

從源src所指的內(nèi)存地址的起始位置開始拷貝n個字節(jié)到目標(biāo)dest所指的內(nèi)存地址的起始位置中跪但。返回指向dest

void * memset(void *buffer,int c,size_t num);

將buffer中前n個字節(jié)用c替換并返回buffer 履羞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市屡久,隨后出現(xiàn)的幾起案子忆首,更是在濱河造成了極大的恐慌,老刑警劉巖被环,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糙及,死亡現(xiàn)場離奇詭異,居然都是意外死亡筛欢,警方通過查閱死者的電腦和手機(jī)浸锨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悴能,“玉大人揣钦,你說我怎么就攤上這事∧穑” “怎么了冯凹?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長炒嘲。 經(jīng)常有香客問我宇姚,道長,這世上最難降的妖魔是什么夫凸? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任浑劳,我火速辦了婚禮,結(jié)果婚禮上夭拌,老公的妹妹穿的比我還像新娘魔熏。我一直安慰自己衷咽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布蒜绽。 她就那樣靜靜地躺著镶骗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪躲雅。 梳的紋絲不亂的頭發(fā)上鼎姊,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音相赁,去河邊找鬼相寇。 笑死,一個胖子當(dāng)著我的面吹牛钮科,可吹牛的內(nèi)容都是我干的唤衫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼跺嗽,長吁一口氣:“原來是場噩夢啊……” “哼战授!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起桨嫁,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤植兰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后璃吧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楣导,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年畜挨,在試婚紗的時候發(fā)現(xiàn)自己被綠了筒繁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡巴元,死狀恐怖毡咏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逮刨,我是刑警寧澤呕缭,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站修己,受9級特大地震影響恢总,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜睬愤,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一片仿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尤辱,春花似錦砂豌、人聲如沸厢岂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咪笑。三九已至可帽,卻和暖如春娄涩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背映跟。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工蓄拣, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人努隙。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓球恤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荸镊。 傳聞我的和親對象是個殘疾皇子咽斧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容