Linux應用編程之——文件IO

Linux應用編程之——文件IO

Linux應用編程之——文件IO

在Linux系統中有一個重要的概念:一切皆文件,它把一切資源都看作是文件,包括硬件設備,通常稱爲設備文件。前面我們也嘗試過通過腳本讀寫文件的方式,實現了對硬件的訪問。所以如果不瞭解Linux的文件操作,那想要點亮開發板的LED燈都費勁!對Linux文件IO的處理,這意味着程序完全可以像使用文件那樣使用磁盤文件,串口,打印機等等。

文件IO操作示意圖

在Linux下,一個與文件操作相關的應用程序結構如下所示。
在這裏插入圖片描述

上圖解構如下:
應用層指用戶編寫的程序,如我們的hello.c。
GNU C庫(glibc)即C語言標準庫,例如在編譯器章節介紹的libc.so.6文件,它 包含了printf、malloc,以及本章使用的fopen、fread、fwrite等文件操作函數。
用戶程序和glibc庫都是屬於用戶空間的,本質都是用戶程序。
應用層的程序和glibc可能會調用到”系統調用層(SCI)”的函數,這些函數 是Linux內核對外提供的函數接口,用戶通過這些函數向系統申請操作。例如,C庫 的printf函數使用了系統的vsprintf和write函數,C庫的fopen、fread、fwrite分別 調用了系統的open、read、w rite函數,具體可以閱讀glibc的源碼瞭解。
由於文件系統種類非常多,跟文件操作相關的open、read、write等函數經過虛 擬文件系統層,再訪問具體的文件系統。
總的來說,爲了使不同的文件系統共存, Linux內核在用戶層與具體文件 系統之前增加了虛擬文件系統中間層,它對複雜的系統進行抽象化,對用戶提供了統 一的文件操作接口。無論是ext2/3/4、FAT32、NTFS存儲的文件,還是/proc、/sys提供 的信息還是硬件設備,無論內容是在本地還是網絡上,都使用 一樣的open、read、write來訪問,使得”一切皆文件”的理念被實現,這也正是軟件中間層的魅力。

常用文件操作(C標準庫)

通用的C標準庫接口訪問文件,標準庫實際是對系統調用再次進行了封裝。使用C標準庫編寫的代碼,能方便地在不同的系統上移植。

操作系統的核心部分,即內核,是由一組設備驅動程序組成。他們是一組對系統硬件進行控制的底層接口,爲了向用戶提供一個一致的接口,其封裝了所有與硬件相關的特性。

fopen詳解:

在這裏說一句,在開發的問題的時候,遇到不熟悉的函數,一定要使用man手冊,而不是老是在網上找答案。

fopen庫函數用於打開或創建文件,返回相應的文件流。
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);

pathname參數用於指定要打開或創建的文件名。
mode參數用於指定文件的打開方式,注意該參數是一個字符串,輸入時需要帶雙引號:
“r”:以只讀方式打開,文件指針位於文件的開頭。
“r+”:以讀和寫的方式打開,文件指針位於文件的開頭。
“w”:以寫的方式打開,不管原文件是否有內容都把原內容清空掉,文件指針位於文件的開頭。
“w+”: 同上,不過當文件不存在時,前面的”w”模式會返回錯誤,而此處的”w+”則會創建新文件。
“a”:以追加內容的方式打開,若文件不存在會創建新文件,文件指針位於文件的末尾。與”w+”的區別是它不會清空原文件的內容而是追加。
“a+”:以讀和追加的方式打開,其它同上。
fopen的返回值是FILE類型的文件文件流,當它的值不爲NULL時表示正常,後續的fread、fwrite等函數可通過文件流訪問對應的文件。

fread詳解:

fread庫函數用於從文件流中讀取數據。
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

fread的返回值爲成功讀取的項數(項的單位爲size)。

fwrite詳解:

fwrite庫函數用於把數據寫入到文件流。
#include <stdio.h>
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);

它的操作與fread相反,把ptr數組中的內容寫入到stream文件流,寫入的項數爲nmemb,每項 大小爲size,返回值爲成功寫入的項數(項的單位爲size)。

fclose詳解:

fclose庫函數用於關閉指定的文件流,關閉時它會把尚未寫到文件的內容都寫出。
因爲標準 庫會對數據進行緩衝,所以需要使用fclose來確保數據被寫出。
#include <unistd.h>
int close(int fd);

它的操作與fread相反,把ptr數組中的內容寫入到stream文件流,寫入的項數爲nmemb,每項 大小爲size,返回值爲成功寫入的項數(項的單位爲size)。

fflush詳解:

fflush函數用於把尚未寫到文件的內容立即寫出。常用於確保前面操作的數據被寫 入到磁盤上。
fclose函數本身也包含了fflush的操作
#include <unistd.h>
int fflush(FILE *stream);

fseek詳解:

fseek函數用於設置下一次讀寫函數操作的位置。
#include <unistd.h>
int fseek(FILE *stream, long offset, int whence);

其中的offset參數用於指定位置,whence參數則定義了offset的意義,whence的可取值如下:

SEEK_SET:offset是一個絕對位置。
SEEK_END:offset是以文件尾爲參考點的相對位置。
SEEK_CUR:offset是以當前位置爲參考點的相對位置。

文件操作(系統調用)

Linux提供的文件操作系統調用常用的有open、write、read、lseek、close等。
別人或許會問,爲什麼上面是fopen,這裏確實open呢?
open 是系統調用 返回的是文件句柄,文件的句柄是文件在文件描述副表裏的索引,fopen是C的庫函數,返回的是一個指向文件結構的指針。
open是linux下的底層系統調用函數,fopen與freopen c/c++下的標準I/O庫函數,帶輸入/輸出緩衝。
一般用fopen打開普通文件,用open打開設備文件,fopen是標準c裏的,而open是linux的系統調用.他們的層次不同.fopen可移植,open不能。

open詳解:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

Linux使用open函數來打開文件,並返回該文件對應的文件描述符。函數參數的具體說明如下:
pathname:要打開或創建的文件名;
flag:指定文件的打開方式,具體有以下參數,見下表 flag參數值。

表 flag參數值
標誌位 含義
O_RDONLY 以只讀的方式打開文件,該參數與O_WRONLY和O_RDWR只能三選一
O_WRONLY 以只寫的方式打開文件
O_RDWR 以讀寫的方式打開文件
O_CREAT 創建一個新文件
O_APPEND 將數據寫入到當前文件的結尾處
O_TRUNC 如果pathname文件存在,則清除文件內容
C庫函數fopen的mode參數與系統調用open的flags參數有如下表中的等價關係。

表 fopen的mode與open的flags參數關係
fopen的mode參數 open的flags參數
r O_RDONLY
w O_WRONLY | O_CREAT | O_TRUNC
a O_WRONLY | O_CREAT | O_APPEND
r+ O_RDWR
w+ O_RDWR | O_CREAT | O_TRUNC
a+ O_RDWR | O_CREAT | O_APPEND

mode:當open函數的flag值設置爲O_CREAT時,必須使用mode參數來設置文件 與用戶相關的權限。mode可用的權限如下表所示,表中各個參數可使用”| “來組 合。
表 文件權限
\ 標誌位 含義
當前用戶 S_IRUSR 用戶擁有讀權限
\ S_IWUSR 用戶擁有寫權限
\ S_IXUSR 用戶擁有執行權限
\ S_IRWXU 用戶擁有讀、寫、執行權限
當前用戶組 S_IRGRP 當前用戶組的其他用戶擁有讀權限
\ S_IWGRP 當前用戶組的其他用戶擁有寫權限
\ S_IXGRP 當前用戶組的其他用戶擁有執行權限
\ S_IRWXG 當前用戶組的其他用戶擁有讀、寫、執行權限
其他用戶 S_IROTH 其他用戶擁有讀權限
\ S_IWOTH 其他用戶擁有寫權限
\ S_IXOTH 其他用戶擁有執行權限
\ S_IROTH 其他用戶擁有讀、寫、執行權限

read詳解:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
ssize_t read(int fd, void *buf, size_t count);

read函數用於從文件中讀取若干個字節的數據,保存到數據緩衝區buf中,並返 回實際讀取的字節數,具體函數參數如下:
fd:文件對應的文件描述符,可以通過fopen函數獲得。另外,當一個程序 運行時,Linux默認有0、1、2這三個已經打開的文件描述符,分別對應了標準輸入、標準輸出、標準錯誤輸出,即可以直接訪問這三種文件描述符;
buf:指向數據緩衝區的指針;
count:讀取多少個字節的數據。

write詳解:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
ssize_t write(int fd, const void *buf, size_t count);

write函數用於往文件寫入內容,並返回實際寫入的字節長度,具體函數參數如下:
fd:文件對應的文件描述符,可以通過fopen函數獲得。
buf:指向數據緩衝區的指針;
count:往文件中寫入多少個字節

close詳解:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int close(int fd);

當我們完成對文件的操作之後,想要關閉該文件,可以調用close函數,來關閉該fd文件描述符對應的文件。

lseek詳解:

lseek函數可以用與設置文件指針的位置,並返回文件指針相對於文件頭 的位置。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
off_t lseek(int fd, off_t offset, int whence);

它的用法與flseek一樣,其中的offset參數用於指定位置,whence參數則定義了offset的意義,whence的可取值如下:
SEEK_SET:offset是一個絕對位置。
SEEK_END:offset是以文件尾爲參考點的相對位置。
SEEK_CUR:offset是以當前位置爲參考點的相對位置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章