本文用於記錄在LINUX編程中,常用的文件操作函數,包括系統調用和庫函數,以備查閱。
針對輸入輸出操作,直接使用底層系統調用的一個問題是它們的效率十分低,原因在於:
1.使用系統調用會影響系統的性能,與函數調用相比,系統調用的開銷要大些,因為在執行系統調用時,Linux必須從運行用戶代碼切換到執行內核代碼,然後再返回用戶代碼。
2.硬件會限制對底層系統調用一次所能讀寫的數據塊大小。比如,磁帶機通常一次能寫的數據塊長度是10K,所以若你試圖寫的數據量不是10K的整數倍,磁帶機還是以10K為單位卷繞磁帶,從而在磁帶上留下空隙
#include <unistd.h>
size_t write(int fildes, const void *buf, size_t nbytes);
系統調用write作用:把緩沖區buf的前nbytes個字節寫入與文件描述符fildes關聯的文件中。它返回實際寫入的字節數,若文件描述符有錯或底層的設備驅動程序對數據塊長度比較敏感,該返回值可能會小於nbytes。如果函數返回0,就表示未寫入任何數據;如果返回-1,就表示write調用中出現了錯誤,錯誤代碼保存在全局變量errno裡。
#include <unistd.h>
size_t read(int fildes, void *buf, size_t nbytes);
系統調用read作用:從與文件描述符fildes關聯的文件裡讀入nbytes個字節的數據,並把它們放到數據區buf中。它返回實際讀入的字節數,該返回值可能會小於請求的字節數。如果函數返回0,就表示未讀入任何數據,已到達文件尾。如果返回-1,就表示read調用中出現了錯誤,錯誤代碼保存在全局變量errno裡。
#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);
系統調用open作用:調用成功返回一個唯一的新文件描述符(總是一個非負整數),失敗時返回-1並設置全局變量errno。准備打開的文件或設備的名字作為參數path傳遞給函數,oflags參數用於指定打開文件所采取的動作。oflags可選參數如下:
當使用帶有O_CREAT標志的open調用來創建文件時,必須使用有3個參數格式的open調用,其中第三個參數mode有以下標志位:
以上這些標志位在頭文件sys/stat.h中定義
#include <unistd.h>
int close(int fildes);
終止文件描述符fildes與其對應文件之間的關聯。文件描述符被釋放並能夠重新使用。close調用成功時返回0,出錯時返回-1
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes, off_t offset, int whence);
offset參數用來指定位置,而whence參數定義偏移值,whence可以取下列值:
lseek返回從文件頭到文件指針被設置處的字節偏移值,失敗時返回-1。
#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);
fstat系統調用返回與打開的文件描述符相關的文件的狀態信息,該信息將會寫入到一個buf結構中,buf的地址以參數形式傳遞給fstat
相關函數stat和lstat返回的是通過文件名查到的狀態信息。它們產生相同的結果,但當文件是一個符號鏈接時,lstat返回的是該符號鏈接本身的信息,而stat返回的是該鏈接指向的文件的信息。
stat結構一般包括如下成員:
stat結構中返回的st_mode標志還有一些與之關聯的宏,它們定義在sys/stat.h中。
這些宏包括對訪問權限、文件類型標志以及一些用於幫助測試特定類型和權限的掩碼的定義。
#include <unistd.h>
int dup(int fildes);
int dup2(int fildes, int fildes2);
dup系統調用提供一種復制文件描述符的方法,使我們能夠通過兩個或更多個不同的描述符來訪問同一個文件。這可以用於在文件的不同位置對數據進行讀寫。dup系統調用復制文件描述符fildes,返回一個新的描述符。dup2系統調用則是通過明確指定目標描述符來把一個文件描述符復制為另外一個。
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
fopen庫函數類似於底層的open系統調用。它主要用於文件和終端的輸入輸出。如果需要對設備進行明確的控制,則最好使用系統調用,因為這可以避免用庫函數帶來的一些潛在問題,如輸入/輸出緩沖。
fopen打開由filename參數指定的文件,並把它與一個文件流關聯起來。mode參數指定文件的打開方式,它取下列字符串中的值:
fopen在成功時返回一個非空的FILE*指針,失敗時返回NULL值,NULL值在stdio.h中定義
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
fread庫函數用於從一個文件流裡讀取數據。數據從文件流stream讀到由ptr指向的數據緩沖區裡。size參數指定每個數據記錄的長度,計數器nitems給出要傳輸的記錄個數。它的返回值是成功讀到數據緩沖區裡的記錄個數(而不是字節數)。當到達文件尾時,它的返回值可能會小於nitems,甚至可以是零。
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
fwrite庫函數用於從指定的數據緩沖區裡取出數據記錄,並把它們寫到輸出流中。size參數指定每個數據記錄的長度,計數器nitems給出要寫的記錄個數。它的返回值是成功寫入的記錄個數(而不是字節數)。當到達文件尾時,它的返回值可能會小於nitems,甚至可以是零。
#include <stdio.h>
int fclose(FILE *stream);
fclose庫函數關閉指定1文件流stream,使所有尚未寫出的數據都寫出。因為stdio庫會對數據進行緩沖,所以使用fclose很重要。當程序正常結束時,會自動對所有還打開的文件流調用fclose函數
#include <stdio.h>
int fflush(FILE *stream);
fflush庫函數的作用是把文件流裡的所有未寫出數據立刻寫出。需要注意的是,fclose函數隱含的調用fflush,所以不必調用fclose之前調用fflush。
#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);
fseek函數是與lseek系統調用對應的文件流函數,它在文件流裡為下一次讀寫操作指定位置。offset和whence參數的含義與取值與lseek系統調用完全一樣,但lseek返回的是一個off_t數值,而fseek返回的是一個整數,0表示成功,-1表示失敗並設置errno指出錯誤。
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar();
fgetc函數從文件流裡取出下一個字節並把它作為一個字符返回。當它到達文件尾或出現錯誤時,它返回EOF。而必須通過ferror或feor函數來區分這兩種情況。getc函數的作用於fgetc一樣,但它有可能被實現為一個宏。而getchar函數則相當於getc(stdin),它從標准輸入裡讀取下一個字符。
#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar();
這三個函數關系與上述三個函數關系類似,putchar相當於putc(c, stdout),它把單個字符寫到標准輸出。需要注意的是,putchar和getchar都是把字符當做int類型而不是char類型來使用,這就允許文件尾(EOF)標識取值-1,這是一個超出字符數字編碼范圍的值。
#include <stdio.h>
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);
fgets函數從輸入文件流stream裡讀取一個字符串到s指向的字符串裡,直到出現下面某種情況:遇到換行符,已經傳輸了n-1個字符,或者到達文件尾。它會把遇到的換行符也傳遞到接收字符串裡,再加上一個表示結尾的空字節\0。一次調用最多只能傳輸n-1個字符,因為它必須把空字節加上以結束字符串。當調用成功返回一個指向字符串s的指針。如果文件流已經到達文件尾,fgets會設置這個文件流的EOF標識並返回一個空指針。如果出現讀錯誤,fgets返回一個空指針並設置errno以指出錯誤的類型。
gets函數類似fgets,但它從標准輸入讀取數據並丟棄遇到的換行符。它在接收字符串的尾部加上一個nul字節。需要注意的是,gets對傳輸字符的個數並沒有限制,所以它可能會溢出自己的傳輸緩沖區。
#include <stdio.h>
int fputs(const char * s, FILE * stream);
int puts(const char *string);
fputs函數將參數s所指的字符串寫到輸出文件流stream中,若調用成功則返回寫出的字符個數,如果返回EOF表示發生寫錯誤。
puts函數類似fputs,它將參數s所指的字符串輸出到標准輸出中。它遇到空字節\0才會停止輸出。並且在輸出完字符串後會自動輸出一個換行符\n
#include <stdio.h>
int printf(const char * format, ...);
int sprintf(char *s, const char * format, ...);
int fprintf(FILE *stream, const char * format, ...);
printf函數把自己的輸出送到標准輸出。fprintf函數則把自己的輸出送到一個指定的文件流。sprintf函數把自己的輸出和一個結尾空字符寫到作為參數傳遞過來的字符串s裡。這個字符串必須足夠容納所有的輸出數據。
#include <stdio.h>
int scanf(const char * format, ...);
int sscanf(const char *s, const char * format, ...);
int fscanf(FILE *stream, const char * format, ...);
scanf函數讀入的值保存到對應的變量裡去,這些變量的類型必須正確,並且它們必須准確匹配格式字符串。否則內存數據就可能會遭到破壞,從而使程序崩潰。scanf系列函數的format格式字符串裡同時包含著普通字符和轉換控制符,那些普通字符是用於指定在輸入數據裡必須出現的字符。
例如 scanf ("Hello %d", &num);
則這個scanf調用只有在標准輸入中接下來的五個字符匹配"Hello"的情況下才會成功。
scanf函數1返回值是它成功讀取的數據項個數,如果在讀第一個數據項時失敗了,則它的返回值是零。如果在匹配第一個數據項之前就已經到達了輸入的結尾,它就會返回EOF。如果文件流發送讀錯誤,流錯誤標志就會被設置並且錯誤變量errno將被設置以指明錯誤類型。
#include <errno.h>
extern int errno;
許多函數都可能改變errno的值,它的值只有在函數調用失敗時才有意義。必須在函數表明失敗之後立刻對其進行檢查。使用之前應該將它先復制到另一個變量中,因為像fprintf這樣的輸出函數本身就可以改變errno的值,也可以通過檢查文件流的狀態來確定是否發生了錯誤,或者是否到達了文件尾。關於錯誤代碼的取值和含義都列在頭文件errno.h中,一般包括:
#include <string.h>
char *strerror(int errnum);
strerror函數把錯誤代碼映射為一個字符串,該字符串對發生的錯誤類型進行說明。
#include <stdio.h>
void perror(const char *s);
perror函數也把errno變量中報告的當前錯誤映射為一個字符串,並把它輸出到標准錯誤輸出流。該字符串的前面先加上字符串s(如果不為空)中給出的信息,再加上一個冒號和一個空格。
#include <stdio.h>
int ferror(FILE *stream);
int feof(FILE *stream);
void clearerr(FILE *stream);
ferror函數測試一個文件流的錯誤標識,如果該標識被設置就返回一個非零值,否則返回0。
feof函數測試一個文件流的文件尾標識,如果該標識被設置就返回一個非零值,否則返回0。
clearerr函數的作用是清除由stream指向的文件流的文件尾標識和錯誤標識。它沒有返回值,也未定義任何錯誤。
#include <stdio.h>
int fileno(FILE *stream);
FILE *fdopen(int fildes, const char *mode);
可以通過調用fileno函數來確定文件流使用的是哪個底層文件操作符。它返回指定文件流使用的文件描述符,如果失敗則返回-1。
可以通過調用fdopen函數在一個已打開的文件描述符上創建一個新的文件流,實質上,該函數作用是為一個已經打開的文件描述符提供stdio緩沖區。
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
chmod系統調用用來改變文件或目錄的訪問權限。參數mode的定義與open系統調用一樣。
#include <sys/types.h>
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
chmod系統調用用來改變一個文件的屬主。調用使用的是用戶ID和組ID的數字值(通過getuid和getgid調用獲得)
#include <unistd.h>
int unlink(const char *path);
int link(const char *path1, const char *path2);
int symlink(const char *path1, const char *path2);
unlink系統調用刪除一個文件的目錄項並減少它的鏈接數。成功時返回0,失敗時返回-1。若要用該系統調用來成功刪除文件,必須擁有該文件所屬目錄的寫和執行權限。如果一個文件的鏈接數減少到零,並且沒有進程打開它,這個文件就會被刪除。
使用link系統調用在程序中創建一個文件的新鏈接。它將創建一個指向已有文件path1的新鏈接,新目錄項由path2給出。
使用symlink系統調用以類似的方法創建符號鏈接,注意,一個文件的符合鏈接並不會增加該文件的鏈接數。
#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);
mkdir系統調用用於創建目錄,它將參數path作為新建目錄的名字。目錄的權限由參數mode設定,其含義將按open系統調用的O_CREAT選項中的有關定義設置。當然還需要服從umask的設置情況。
#include <unistd.h>
int rmdir(const char *path);
rmdir系統調用用於刪除目錄,但只有在目錄為空時才行。
#include <unistd.h>
int chdir(const char *path);
chdir系統調用用於改變工作目錄。
#include <unistd.h>
char *getcwd(char *buf, size_t size);
getcwd系統調用用於把當前目錄的名字寫到給定的緩沖區buf裡。如果目錄名的長度超出了參數size給出的緩沖區長度(一個ERANGE錯誤),它就返回NULL,如果成功,它返回指針buf。需要注意的是,如果程序運行過程中,目錄被刪除(EINVAL錯誤)或者有關權限發生了變化(EACCESS錯誤),getcwd也可能會返回NULL。
#include <sys/types.h>
#Include <dirent.h>
DIR *opendir(const char *name);
opendir函數的作用是打開一個目錄並建立一個目錄流。如果成功,它返回一個指向DIR結構的指針,該指針用於讀取目錄數據項。opendir在失敗時返回一個空指針(NULL)。
#include <sys/types.h>
#Include <dirent.h>
struct dirent *readdir(DIR *dirp);
readdir函數返回一個指針,該指針指向的結構裡保存著目錄流dirp中下一個目錄項的有關資料。後續的readdir調用將返回後續的目錄項。如果發生錯誤或到達目錄尾,readdir將返回NULL。當到達目錄尾時會返回NULL,但並不改變errno的值,只有在發生錯誤時才會設置errno。需要注意的是,如果在readdir函數掃描目錄的同時還有其他進程在該目錄裡創建或刪除文件,readdir將不保證能夠列出該目錄裡的所有文件(和子目錄)。
#include <sys/types.h>
#Include <dirent.h>
long int telldir(DIR *dirp);
telldir函數的返回值記錄著一個目錄流裡的當前位置。
#include <sys/types.h>
#Include <dirent.h>
void seekdir(DIR *dirp, long int loc);
seekdir函數的作用是設置目錄流dirp的目錄項指針。loc的值用來設置指針位置,它通過telldir調用獲得。
#include <sys/types.h>
#Include <dirent.h>
int closedir(DIR *dirp);
closedir函數的作用是關閉一個目錄流並釋放與之關聯的資源。執行成功返回0,發生錯誤時返回-1。
其他流函數:
int fgetpos( FILE *stream, fpos_t *pos );
獲得文件流的當前(讀寫)位置
int fsetpos(FILE *fp, const fpos_t *pos);
設置文件流的當前(讀寫)位置
long ftell(FILE *fp);
返回文件流的當前(讀寫)位置的偏移值
void rewind(FILE *stream);
rewind:重置文件流裡的讀寫位置
FILE *freopen( const char *path, const char *mode, FILE *stream );
實現重定向,把預定義的標准流文件定向到由path指定的文件中。
void setbuf(FILE *stream,char *buf);
void setvbuf(FILE *stream,char *buf,int type,unsigned size);
設置文件流的緩沖機制,用戶可建立自己的文件緩沖區,而不使用fopen()函數打開文件設定的默認緩沖區。對於setbuf()函數,buf指出的緩沖區長度由頭文件stdio.h中定義的宏BUFSIZE的值決定,缺省值為512字節。當選定buf為空時,setbuf函數將使的文件I/O不帶緩沖。而對setvbuf函數,則由malloc函數來分配緩沖區。參數size指明了緩沖區的長度(必須大於0),而參數type則表示了緩沖的類型,其值可以取如下值:
type 值 含義
_IOFBF 文件全部緩沖,即緩沖區裝滿後,才能對文件讀寫
_IOLBF 文件行緩沖,即緩沖區接收到一個換行符時,才能對文件讀寫
_IONBF 文件不緩沖,此時忽略buf,size的值,直接讀寫文件,不再經過文件緩沖區緩沖
int remove(char *path);
相當於unlink函數,但如果它的path參數是一個目錄,其作用則相當於rmdir函數