Linux文件IO操作
文件操作是linux系統(tǒng)中最常見(jiàn)的操作之一,關(guān)于文件的輸入輸出操作,分為基于文件描述符的I/O操作和基于流的I/O操作。本篇介紹基于文件描述符的I/O操作。
文件類型
首先介紹下linux系統(tǒng)中文件的各種類型與符號(hào)表示。
基于文件描述符的I/O操作
文件描述符
Linux操作系統(tǒng)內(nèi)核利用文件描述符來(lái)訪問(wèn)文件,文件描述符是一個(gè)非負(fù)整數(shù),用于描述被打開(kāi)文件的索引值,它指向該文件的相關(guān)信息記錄表。
文件描述符的有效范圍是0到1023,其中0、1、2分別用于標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò)。
文件重定向
重定向標(biāo)準(zhǔn)輸出
不使用系統(tǒng)標(biāo)準(zhǔn)輸出的默認(rèn)設(shè)備,而是將輸出結(jié)果直接寫(xiě)在一個(gè)新的文件中,命令格式如下:
command 1> filename # 把標(biāo)準(zhǔn)輸出重定向到filename文件中 command > filename # 把標(biāo)準(zhǔn)輸出重定向到filename文件中 command >> filename # 把標(biāo)準(zhǔn)輸出重定向到filename文件中,方式是追加在現(xiàn)有內(nèi)容的后面 > myfile # 創(chuàng)建一個(gè)長(zhǎng)度為0的空文件
command代表用戶所熟悉的shell命令
重定向標(biāo)準(zhǔn)輸入
不使用系統(tǒng)標(biāo)準(zhǔn)輸入的默認(rèn)設(shè)備,而是引用其它文件的內(nèi)容或是其它命令的輸出,命令格式如下:
command < filename # 以filename文件的內(nèi)容作為command命令的標(biāo)準(zhǔn)輸入 command < file1 > file2 # 以file1文件的內(nèi)容作為command命令的標(biāo)準(zhǔn)輸入,并以file2文件的內(nèi)容作為command命令的標(biāo)準(zhǔn)輸出 command << delimiter # 從標(biāo)準(zhǔn)輸入中讀入,直到遇到delimiter分界符
重定向標(biāo)準(zhǔn)出錯(cuò)
將系統(tǒng)指向的錯(cuò)誤信息重定向到一個(gè)文件中,而不使用默認(rèn)的顯示器等輸出設(shè)備,命令格式如下:
command 2> filename # 把標(biāo)準(zhǔn)出錯(cuò)信息重定向到filename文件中 command 2>> filename # 把標(biāo)準(zhǔn)出錯(cuò)信息重定向到filename文件中(追加)
文件的創(chuàng)建、打開(kāi)、關(guān)閉
open()函數(shù)
調(diào)用該函數(shù)可以打開(kāi)或創(chuàng)建一個(gè)文件,函數(shù)原型為:
#include
運(yùn)行成功返回文件描述符,運(yùn)行出錯(cuò)返回-1。
參數(shù)flag用于描述文件的打開(kāi)方式。
參數(shù)mode用于指定所創(chuàng)建文件的權(quán)限。
使用open函數(shù)打開(kāi)或創(chuàng)建一個(gè)文件,open_file.c:
#include
編譯后執(zhí)行:
$ ./open_file Input the pathname[<30 strings]:./hello.txt OK, open file successful! fd=3
程序在當(dāng)前目錄創(chuàng)建了hello.txt文件,進(jìn)一步查看該文件的信息:
ls -l hello.txt -rwxr-xr-x 1 deeplearning deeplearning 0 12月 20 19:59 hello.txt
可以看到文件的權(quán)限為rwxr-xr-x,與程序中的MODE宏定義一致。
create()函數(shù)
用于創(chuàng)建文件,函數(shù)原型為:
#include
運(yùn)行成功返回以只寫(xiě)方式打開(kāi)的文件描述符,運(yùn)行出錯(cuò)返回-1。
close()函數(shù)
用于關(guān)閉文件,函數(shù)原型為:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
文件的定位
每個(gè)已打開(kāi)的文件都有一個(gè)與其相關(guān)聯(lián)的“當(dāng)前文件位移量”,它是一個(gè)非負(fù)整數(shù),用以度量從文件開(kāi)始處計(jì)算的字節(jié)數(shù)。可以調(diào)用lseek()函數(shù)顯示地定位一個(gè)打開(kāi)文件,函數(shù)原型為:
#include
運(yùn)行成功返回文件位移量,運(yùn)行出錯(cuò)返回-1。
測(cè)試標(biāo)準(zhǔn)輸入能否被設(shè)置位移量,offset_test.c:
#include
編譯后執(zhí)行:
$ ./offset_test can't seek! $ ./offset_test < ./hello.txt seek OK!
可以看出,對(duì)于標(biāo)準(zhǔn)輸入,一般不能設(shè)置位移量,而用戶創(chuàng)建的一般文件可以設(shè)置位移量。
文件的讀寫(xiě)
read()函數(shù)
用read()函數(shù)從打開(kāi)文件中讀取數(shù)據(jù),函數(shù)原型為:
#include
運(yùn)行成功返回讀到的字節(jié)數(shù),若已到文件尾返回0,運(yùn)行出錯(cuò)返回-1。
參數(shù)fd表示文件描述符,參數(shù)buf為指向緩沖區(qū)的指針,參數(shù)count表示本次操作將要讀取的字節(jié)數(shù)。
實(shí)際讀取的字節(jié)數(shù)有時(shí)會(huì)少于要求讀取的字節(jié)數(shù):
讀普通文件時(shí),在讀到要求的字節(jié)數(shù)之前到達(dá)文件尾
從終端設(shè)備讀時(shí),通常一次讀取一行
從網(wǎng)絡(luò)中讀時(shí),網(wǎng)絡(luò)中的緩沖機(jī)構(gòu)可能造成返回值小于所要求讀的字節(jié)數(shù)
write()函數(shù)
用write()函數(shù)向打開(kāi)文件中寫(xiě)數(shù)據(jù),函數(shù)原型為:
#include
運(yùn)行成功返回已寫(xiě)的字節(jié)數(shù),運(yùn)行出錯(cuò)返回-1。
參數(shù)fd表示文件描述符,參數(shù)buf為指向緩沖區(qū)的指針,參數(shù)count表示本次操作將要寫(xiě)入的字節(jié)數(shù)。
函數(shù)返回值通常與參數(shù)count的值相同,否則表示出錯(cuò)。出錯(cuò)的原因通常是磁盤已寫(xiě)滿或超過(guò)了對(duì)一個(gè)給定進(jìn)程的文件長(zhǎng)度限制。
使用write函數(shù)向文件寫(xiě)入數(shù)據(jù),write_file.c:
#include
編譯后執(zhí)行:
$ ./write_file OK, open file successful! Begin Write: hello,linux C! OK, write 14 strings to file!
查看hello.txt:
$ cat hello.txt hello,linux C!
文件的屬性操作
改變文件訪問(wèn)權(quán)限
chmod()、fchmod()這兩個(gè)函數(shù)使用戶可以更改現(xiàn)存文件的存取許可權(quán):
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
chmod(),在指定的文件上進(jìn)行操作,pathname指定了文件的絕對(duì)或相對(duì)路徑名
fchmod(),在已打開(kāi)的文件上進(jìn)行操作,fd是文件描述符,mode為文件的權(quán)限
使用chmod函數(shù)改變文件的訪問(wèn)權(quán)限,change_mode.c:
#include
編譯后執(zhí)行:
$ ./change_mode OK, change successful!
進(jìn)一步查看該文件的信息:
$ ls -l hello.txt -rwx------ 1 deeplearning deeplearning 14 12月 20 20:09 hello.txt
可以看到文件的權(quán)限為rwxr-----,與程序中的MODE宏定義(0755)一致。
改變文件所有者
有3個(gè)函數(shù)可以改變一個(gè)文件的所有者識(shí)別號(hào)和用戶組識(shí)別號(hào),函數(shù)原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
chown(),修改指定文件的所有者
fchown(),修改已打開(kāi)文件的所有者
lchown(),修改符號(hào)鏈接文件本身的所有者
重命名
對(duì)文件或目錄文件重命名,函數(shù)原型:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
修改文件的長(zhǎng)度
截短文件可以調(diào)用truncate()和ftruncate(),函數(shù)原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
文件的其它操作
stat、fsat、lstat函數(shù)
Linux系統(tǒng)中所有文件都有一個(gè)與之對(duì)應(yīng)的索引節(jié)點(diǎn),該節(jié)點(diǎn)包含了文件的相關(guān)信息,這些信息被保存在stat結(jié)構(gòu)體中,可以調(diào)用下面3個(gè)stat函數(shù)來(lái)返回文件的信息:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
stat結(jié)構(gòu)體基本形式如下:
struct stat { mode_t st_mode; // 文件類型&模式 ino_t st_ino; // i-node號(hào) dev_t st_dev; // 設(shè)備號(hào) dev_t st_rdev; // 設(shè)備號(hào)(特殊文件) nlink_t st_nlinkl;// 鏈接號(hào) uid_t st_uid; // 用戶ID gid_t st_gid; // 組ID off_t st_size; time_t st_atime; // access time_t st_mtime; // modification time_t st_ctime; // file station change unsigned long st_blksize; unsigned long st_blocks; }
dup、dup2函數(shù)
這兩個(gè)函數(shù)可以用來(lái)復(fù)制一個(gè)現(xiàn)存的文件描述符,原型如下:
#include
運(yùn)行成功返回新的文件描述符,運(yùn)行出錯(cuò)返回-1。
fcntl函數(shù)
該函數(shù)可以改變已打開(kāi)文件的性質(zhì),原型如下:
#include
運(yùn)行成功依賴于cmd,運(yùn)行出錯(cuò)返回-1。
sync、fsync函數(shù)
為保證磁盤上實(shí)際文件系統(tǒng)與緩存中內(nèi)容的一致性,Linux系統(tǒng)提供了兩個(gè)系統(tǒng)調(diào)用函數(shù),原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
特殊文件的操作
目錄文件的操作
mkdir、rmdir函數(shù)
mkdir用于創(chuàng)建目錄,原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
rmdir用于刪除目錄,原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
opendir 、closedir、readdir函數(shù)
opendir用于打開(kāi)目錄,原型如下:
#include
運(yùn)行成功返回指針,運(yùn)行出錯(cuò)返回NULL。
closedir用于關(guān)閉目錄,原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
readdir用于讀取目錄,原型如下:
#include
運(yùn)行成功返回指針,運(yùn)行出錯(cuò)返回NULL。
函數(shù)返回值指向的結(jié)構(gòu)體指針定義為:
struct dirent { ino_t d_ino; char d_name[NAME_MAX+1]; }
chdir、fchdir、getcwd函數(shù)
進(jìn)程調(diào)用chdir或fchdir函數(shù)可以更改當(dāng)前工作目錄,函數(shù)原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
這兩個(gè)函數(shù),可以分別用pathname或文件描述符來(lái)指定新的當(dāng)前工作目錄。
獲取當(dāng)前工作目錄的絕對(duì)路徑,使用getcwd函數(shù),函數(shù)原型為:
#include
運(yùn)行成功返回buf,運(yùn)行出錯(cuò)返回NULL。
向此函數(shù)傳遞兩個(gè)參數(shù),一個(gè)是緩存地址buf,另一個(gè)是緩存的長(zhǎng)度size,該緩存必須有足夠的長(zhǎng)度以容納絕對(duì)路徑名再加上一個(gè)NULL終止符,否則返回出錯(cuò)。
改變并獲取當(dāng)前的工作目錄,change_path.c:
#include
先查看當(dāng)前的工作目錄:
$ pwd /home/deeplearning/dcj/linuxCTest/fileIO
編譯后執(zhí)行:
$ ./change_path Input the new pathname[<30 strings]:/home/deeplearning OK, change directory successful! cwd=/home/deeplearning
再次使用pwd查看當(dāng)前的工作目錄,理論上應(yīng)該已經(jīng)切換到新的目錄(但是我這里測(cè)試沒(méi)有切換成功,原因未知)。
鏈接文件的操作
硬鏈接
創(chuàng)建一個(gè)硬鏈接使用link函數(shù),原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
此函數(shù)創(chuàng)建一個(gè)新目錄項(xiàng)pathname2,它引用現(xiàn)存文件pathname1,若pathname2已存在則返回出錯(cuò)。
硬鏈接要求兩文件路徑位于同一文件系統(tǒng)中,且只有超級(jí)用戶root才可以創(chuàng)建指向一個(gè)目錄的新鏈接。
刪除一個(gè)硬鏈接使用unlink函數(shù),原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
也可以使用remove函數(shù)解除對(duì)一個(gè)文件或目錄的連接。對(duì)于文件,remove的功能與unlink相同,對(duì)于目錄,remove的功能與rmdir相同。
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
符號(hào)鏈接
符號(hào)鏈接是對(duì)一個(gè)文件的間接指針。
symlink函數(shù)用于創(chuàng)建一個(gè)符號(hào)鏈接,原型如下:
#include
運(yùn)行成功返回0,運(yùn)行出錯(cuò)返回-1。
參考:《精通Linux C編程》- 程國(guó)鋼
Linux
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。