linux gcc编译下的文件读写操作
linux下的文件操作
| 所有目錄 ??????????? 1.文件及文件系統(tǒng)的定義 ??????????? 2.linux文件的類(lèi)型 ??????????? 3.linux文件的權(quán)限 ??????????? 4.文件操作 ??????????????????? 4.1 文件的創(chuàng)建 ??????????????????? 4.2 文件的打開(kāi)及關(guān)閉 ??????????????????? 4.3 文件的讀寫(xiě)操作 ??????????????????? 4.4 文件上鎖 ??????????????????? 4.5 文件的定位 ??????????????????? 4.6 特殊文件的操作 ???????????????????????????? 4.6.1 目錄文件的操作 ???????????????????????????? 4.6.2 鏈接文件的操作 ??????????? 5.部分函數(shù)說(shuō)明 ************************************************************* 正文 ************************************************************* 1.文件及文件系統(tǒng)的定義 ?????? 文件是指有名字的一組相關(guān)信息的集合。文件系統(tǒng)是指按照一定規(guī)律組織起來(lái)的有序的文件組織結(jié)構(gòu),是構(gòu)成系統(tǒng)中所有數(shù)據(jù)的基礎(chǔ)。linux系統(tǒng)中,文件的準(zhǔn)確定義是不包含有任何其他結(jié)構(gòu)的字符流。換句話(huà)說(shuō),文件中的字符和字符之間除了同屬于一個(gè)文件之外,不存在任何其他的關(guān)系。linux系統(tǒng)提供的文件系統(tǒng),是樹(shù)形層次結(jié)構(gòu)系統(tǒng)。Linux中常用的文件系統(tǒng)主要有ext3、ext2及reiserfs 。 2.linux文件的類(lèi)型 ?????? linux下最常見(jiàn)的文件類(lèi)型有5種,它們是普通文件,目錄文件,鏈接文件,字符設(shè)備文件和塊設(shè)備文件,管道文件,套接口文件。 ?????? 我們用 ls -lh 來(lái)查看某個(gè)文件的屬性,可以看到有類(lèi)似 -rw-r--r-- ,值得注意的是第一個(gè)符號(hào)是 - ,這樣的文件在Linux中就是普通文件。這些文件一般是用一些相關(guān)的應(yīng)用程序創(chuàng)建,比如圖像工具、文檔工具、歸檔工具... .... 或 cp工具等。這類(lèi)文件的刪除方式是用rm 命令。當(dāng)我們?cè)谀硞€(gè)目錄下執(zhí)行,看到有類(lèi)似 drwxr-xr-x ,這樣的文件就是目錄,目錄在Linux是一個(gè)比較特殊的文件。注意它的第一個(gè)字符是d。創(chuàng)建目錄的命令可以用 mkdir 命令,或cp命令,cp可以把一個(gè)目錄復(fù)制為另一個(gè)目錄。刪除用rm 或rmdir命令。我們可以看到/dev/tty的屬性是 crw-rw-rw- ,注意前面第一個(gè)字符是 c ,這表示字符設(shè)備文件。比如貓等串口設(shè)備我們看到 /dev/hda1 的屬性是 brw-r----- ,注意前面的第一個(gè)字符是b,這表示塊設(shè)備,比如硬盤(pán),光驅(qū)等設(shè)備;這個(gè)種類(lèi)的文件,是用mknode來(lái)創(chuàng)建,用rm來(lái)刪除。目前在最新的Linux發(fā)行版本中,我們一般不用自己來(lái)創(chuàng)建設(shè)備文件。因?yàn)檫@些文件是和內(nèi)核相關(guān)聯(lián)的。當(dāng)我們啟動(dòng)MySQL服務(wù)器時(shí),會(huì)產(chǎn)生一個(gè)mysql.sock的文件。注意這個(gè)文件的屬性的第一個(gè)字符是 s。我們了解一下就行了。當(dāng)我們查看文件屬性時(shí),會(huì)看到有類(lèi)似 lrwxrwxrwx,注意第一個(gè)字符是l,這類(lèi)文件是鏈接文件。是通過(guò)ln -s 源文件名 新文件名 。上面是一個(gè)例子,表示setup.log是install.log的軟鏈接文件。怎么理解呢?這和Windows操作系統(tǒng)中的快捷方式有點(diǎn)相似。 ??????? 這兒有個(gè)程序,他可以列出當(dāng)前目錄下的文件信息,以及系統(tǒng)“/dev/sda1”和“/dev/lp0”的文件信息。 #include <cstring> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { ??? int newret; ??? printf("列出當(dāng)前目錄下的文件信息:\n"); ??? newret=system("ls -l"); ??? printf("列出“/dev/sda1”的文件信息:\n"); ??? newret=system("ls /dev/sda1 -l"); ??? printf("列出“/dev/ lp0”的文件信息:\n"); ??? newret=system("ls /dev/lp0 -l"); ??? return 0; } 大家可以調(diào)試一下。其中system()函數(shù)說(shuō)明如下:表頭文件 ??????? #i nclude<stdlib.h> 定義函數(shù) ??????? int system(const char * string); 函數(shù)說(shuō)明 ??????? system()會(huì)調(diào)用fork()產(chǎn)生子進(jìn)程,由子進(jìn)程來(lái)調(diào)用/bin/sh-c string來(lái)執(zhí)行參數(shù)string字符串所代表的命令,此命>令執(zhí)行完后隨即返回原調(diào)用的進(jìn)程。在調(diào)用system()期間SIGCHLD 信號(hào)會(huì)被暫時(shí)擱置,SIGINT和SIGQUIT 信號(hào)則會(huì)被忽略。 返回值 ? =-1:出現(xiàn)錯(cuò)誤?? ? =0:調(diào)用成功但是沒(méi)有出現(xiàn)子進(jìn)程?? ? >0:成功退出的子進(jìn)程的id ??????? 如果system()在調(diào)用/bin/sh時(shí)失敗則返回127,其他失敗原因返回-1。若參數(shù)string為空指針(NULL),則返回非零值>。 如果system()調(diào)用成功則最后會(huì)返回執(zhí)行shell命令后的返回值,但是此返回值也有可能為 system()調(diào)用/bin/sh失敗所返回的127,因此最好能再檢查errno 來(lái)確認(rèn)執(zhí)行成功。 附加說(shuō)明 ??????? 在編寫(xiě)具有SUID/SGID權(quán)限的程序時(shí)請(qǐng)勿使用system(),system()會(huì)繼承環(huán)境變量,通過(guò)環(huán)境變量可能會(huì)造成系統(tǒng)安全的問(wèn)題。 3.文件的權(quán)限 ??????? linux文件的權(quán)限可分為四種:可讀取(Readable),可寫(xiě)入(writable),可執(zhí)行(eXecute)和無(wú)權(quán)限,分別用r,w,x和-表示。在linux系統(tǒng)中,對(duì)于任意一個(gè)文件來(lái)說(shuō),他都有一個(gè)特定的所有者,也是創(chuàng)建此文件的用戶(hù),同時(shí),由于linux中用戶(hù)是按組分類(lèi)的,一個(gè)用戶(hù)屬于一個(gè)或多個(gè)組。文件所有者以外的用戶(hù),又可以分為文件所有者的同組用戶(hù)和其他用戶(hù)。因此,linux系統(tǒng)按文件所有者,文件所有者同組用戶(hù)和其他用戶(hù)三類(lèi)規(guī)定了了不同的文件訪(fǎng)問(wèn)權(quán)限。用ls -lh顯示的作為權(quán)限的10個(gè)字符,可分為四部分:1).第一位:一般表示文件類(lèi)型。2).第二到第四位:表示文件所有者的訪(fǎng)問(wèn)權(quán)限。3).第五位到第七位:表示文件所有者同組用戶(hù)的訪(fǎng)問(wèn)權(quán)限。4).第八位到第十位:表示其他用戶(hù)的訪(fǎng)問(wèn)權(quán)限。上面介紹了system()函數(shù),可以用system函數(shù)編程來(lái)實(shí)現(xiàn)對(duì)文件權(quán)限的修改。當(dāng)然還有個(gè)chmod()函數(shù)也可以用來(lái)設(shè)置文件的權(quán)限。如果希望每個(gè)新建的文件都能被賦予某種權(quán)限,則需要由系統(tǒng)的權(quán)限掩碼設(shè)置函數(shù)umask來(lái)決定。下面關(guān)于umask函數(shù)的用法有個(gè)例子。 #include <cstring> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { ??? mode_t new_umask,old_umask; ??? new_umask=0666; ??? old_umask=umask(new_umask); ??? printf("系統(tǒng)原來(lái)的權(quán)限掩碼是:%o\n",old_umask); ??? printf("系統(tǒng)新的權(quán)限掩碼是:%o\n",new_umask); ??? system("touch hu1"); ??? printf("創(chuàng)建了文件hu1\n"); ??? new_umask=0444; ??? old_umask=umask(new_umask); ??? printf("系統(tǒng)原來(lái)的權(quán)限掩碼是:%o\n",old_umask); ??? printf("系統(tǒng)新的權(quán)限掩碼是:%o\n",new_umask); ??? system("touch hu2"); ??? printf("創(chuàng)建了文件hu2\n"); ??? system("ls hu1 hu2 -l"); ??? return 0; } 該程序的運(yùn)行結(jié)果是:系統(tǒng)原來(lái)的權(quán)限掩碼是:22 系統(tǒng)新的權(quán)限掩碼是:666 創(chuàng)建了文件hu1 系統(tǒng)原來(lái)的權(quán)限掩碼是:666 系統(tǒng)新的權(quán)限掩碼是:444 創(chuàng)建了文件hu2 ---------- 1 hubin hubin 0 2009-08-02 11:07 hu1 --w--w--w- 1 hubin hubin 0 2009-08-02 11:07 hu2 程序結(jié)果說(shuō)明:先將系統(tǒng)的權(quán)限掩碼為0666,所以新建的文件hu1訪(fǎng)問(wèn)權(quán)限為0000,即"--------".再將系統(tǒng)的權(quán)限掩碼為0444,所以新建的文件hu2訪(fǎng)問(wèn)權(quán)限為0444,即"--w--w--w-".語(yǔ)句system("touch hu1")的作用是調(diào)用system函數(shù)來(lái)運(yùn)行shell命令"touch hu1",touch命令的作用是更改時(shí)間標(biāo)記,如文件不在,則新建文件。 unmask函數(shù)說(shuō)明: 所需頭文件:#include <sys/types.h> ??????????????????? #include <sys/stat.h> 函數(shù)功能:設(shè)置建立新文件時(shí)的權(quán)限掩碼 函數(shù)原型:mode_t umask(mode_t mask); 函數(shù)傳入值:4位八進(jìn)制數(shù) 函數(shù)返回值:返回值為原先系統(tǒng)的umask值 ?????? 要想獲得文件的其他屬性,可以使用stat函數(shù)或者是fstat函數(shù),其函數(shù)說(shuō)明如下,例子見(jiàn)附件的st_mode.c. 函數(shù)原型 #include <sys/stat.h> int stat(const char *restrict?pathname, struct stat *restrict?buf); 提供文件名字,獲取文件對(duì)應(yīng)屬性。 int fstat(int?filedes, struct stat *buf); 通過(guò)文件描述符獲取文件對(duì)應(yīng)的屬性。 int lstat(const char *restrict?pathname, struct stat *restrict?buf); 連接文件描述命,獲取文件屬性。 2 文件對(duì)應(yīng)的屬性 struct stat { ??????? mode_t???? st_mode;?????? //文件對(duì)應(yīng)的模式,文件,目錄等 ??????? ino_t????? st_ino;?????? //inode節(jié)點(diǎn)號(hào) ??????? dev_t????? st_dev;??????? //設(shè)備號(hào)碼 ??????? dev_t????? st_rdev;?????? //特殊設(shè)備號(hào)碼 ??????? nlink_t??? st_nlink;????? //文件的連接數(shù) ??????? uid_t????? st_uid;??????? //文件所有者 ??????? gid_t????? st_gid;??????? //文件所有者對(duì)應(yīng)的組 ??????? off_t????? st_size;?????? //普通文件,對(duì)應(yīng)的文件字節(jié)數(shù) ??????? time_t???? st_atime;????? //文件最后被訪(fǎng)問(wèn)的時(shí)間 ??????? time_t???? st_mtime;????? //文件內(nèi)容最后被修改的時(shí)間 ??????? time_t???? st_ctime;????? //文件狀態(tài)改變時(shí)間 ??????? blksize_t st_blksize;??? //文件內(nèi)容對(duì)應(yīng)的塊大小 ??????? blkcnt_t?? st_blocks;???? //偉建內(nèi)容對(duì)應(yīng)的塊數(shù)量 ????? }; 可以通過(guò)上面提供的函數(shù),返回一個(gè)結(jié)構(gòu)體,保存著文件的信息。 4.文件操作 ??????? Linux系統(tǒng)把目錄,設(shè)備和連接等操作都等同于文件的操作。它通過(guò)一個(gè)文件描述符來(lái)進(jìn)行區(qū)分和引用特定的文件。文件描述符是一個(gè)非負(fù)的整數(shù),是一個(gè)索引值,指向內(nèi)核中每個(gè)進(jìn)程打開(kāi)的文件的記錄表。 ??????? Linux系統(tǒng)中,基于文件描述符的文件的操作有:不帶緩存的文件I/O操作和帶緩存的流文件I/O操作。不帶緩存的文件I/O操作又稱(chēng)系統(tǒng)調(diào)用I/O操作,符合POSIX標(biāo)準(zhǔn),設(shè)計(jì)的程序能在兼容POSIX標(biāo)準(zhǔn)的系統(tǒng)間方便的移植。主要的函數(shù)有:creat,open,close,read,write,lseek,flock,fcntl等。帶緩存的流文件I/O操作是在內(nèi)存開(kāi)辟一個(gè)“緩存區(qū)”,為程序中的每一個(gè)文件使用。帶緩存的文件I/O操作又稱(chēng)標(biāo)準(zhǔn)I/O操作,符合ANSI C標(biāo)準(zhǔn),比不帶緩存的文件I/O程序方便移植。主要函數(shù)有fopen,fclose,fgetc,fputc,fgets,fread,fwrite,fseek,rewind,ftell等。由于流文件的I/O操作在C語(yǔ)言經(jīng)常用到,一般的C語(yǔ)言書(shū)上也有介紹,所以就不多說(shuō)了,其函數(shù)原型見(jiàn)部分函數(shù)說(shuō)明。 4.1 文件的創(chuàng)建。 ?????? 在linuxC程序設(shè)計(jì)中,創(chuàng)建文件可以調(diào)用creat函數(shù)。 ?????? int creat(const char *filename, mode_t mode); 參數(shù)mode指定新建文件的存取權(quán)限,它同umask一起決定文件的最終權(quán)限(mode&umask),其中umask代表了文件在創(chuàng)建時(shí)需要去掉的一些存取權(quán)限。umask可通過(guò)系統(tǒng)調(diào)用umask()來(lái)改變:下面有個(gè)例子說(shuō)明該函數(shù)的用法,程序是在“/home”目錄下創(chuàng)建一個(gè)“file”的文件,并把此文件的權(quán)限為所有者具有只讀權(quán)限。 #include <cstring> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { ??? int fd; ??? fd=creat("/home/file",S_IRUSR);/*所有者具有只讀權(quán)限*/ ??? system("ls /home/file -l"); ??? return 0; } 有興趣的可以調(diào)一下。如果所創(chuàng)建的文件原本就存在,則就不能創(chuàng)建該文件了。 附creat函數(shù)的說(shuō)明: creat函數(shù):創(chuàng)建一個(gè)文件 相關(guān)頭文件:#include 函數(shù)表達(dá)式:int creat(const char *pathname,mode_t mode); 參數(shù)說(shuō)明:參數(shù)pathname表示需要?jiǎng)?chuàng)建的文件的路徑。參數(shù)mode表示文件的文件權(quán)限。 返回值說(shuō)明:如果成功創(chuàng)建一個(gè)文件則返回新的文件描述符,失敗則返回-1. 函數(shù)功能詳解:creat函數(shù)創(chuàng)建一個(gè)新文件,并以“只寫(xiě)”的方式打開(kāi),返回新文件的文描述符。 函數(shù)使用說(shuō)明: ? ?? ?? ? crea函數(shù)用于創(chuàng)建一個(gè)文件,并且將其以“只寫(xiě)” 形式打開(kāi)。因此程序是無(wú)法讀該文件的。如果需要讀這個(gè)新文件中的內(nèi)容,則必須將其關(guān)閉后從新打開(kāi)。 ? ?? ?? ? creat函數(shù)的第一個(gè)參數(shù)表示的文件不存在,則創(chuàng)建該文件并且以“只寫(xiě)”方式打開(kāi);如果該文件愛(ài)你存在則將其截短謂0,再以“只寫(xiě)”方式打開(kāi)。因此使用creat函數(shù)要注意文件重名時(shí)可能帶來(lái)的問(wèn)題。以下是定義于?<sys/stat.h>?中的九種文件訪(fǎng)問(wèn)權(quán)限位(用于構(gòu)成參數(shù) mode): ????????? S_IRUSR?? // user-read(文件所有者讀) ????????? S_IWUSR?? // user-write(文件所有者寫(xiě)) ????????? S_IXUSR?? // user-execute(文件所有者執(zhí)行) ????????? S_IRGRP?? // group-read ????????? S_IWGRP?? // group-write ????????? S_IXGRP?? // group-execute ????????? S_IROTH?? // other-read ????????? S_IWOTH?? // other-write ????????? S_IXOTH?? // other-execute 其中 user 指文件所有者,group 指文件所有者所在的組,other 指其他用戶(hù)。 creat 函數(shù)只能以只讀方式創(chuàng)建新文件。如果我們要以讀寫(xiě)方式創(chuàng)建新文件,可以用 open 函數(shù):由于open函數(shù)比creat函數(shù)好用,所以open函數(shù)用得較多。 4.2 文件的打開(kāi)和關(guān)閉 ????? 文件的打開(kāi)可以用open,fopen函數(shù)。關(guān)閉用close和fclose函數(shù)。open和close屬于不帶緩存的文件I/O操作而fopen和fclose函數(shù)屬于流文件操作。當(dāng)用open函數(shù)時(shí),即使原來(lái)的文件不存在,也可以用open函數(shù)創(chuàng)建文件。在打開(kāi)或者創(chuàng)建文件時(shí),可以指定文件的屬性及用戶(hù)的權(quán)限等參數(shù)。close函數(shù)則關(guān)閉一個(gè)打開(kāi)的文件而fopen和fclose函數(shù)在C語(yǔ)言編程就用得很多了,這里就不舉例子 例:要求在“./home”下以可讀寫(xiě)的方式打開(kāi)一個(gè)名為"file"的文件。如果該文件不存在,則創(chuàng)建此文件;如果存在,將文件清空后關(guān)閉。 #include <stdio.h> #include <stdlib.h> #include <fcntl.h> int main() { ??? int fd; ??? if((fd=open("/home/file",O_CREAT|O_TRUNC|O_WRONLY,0600))<0) ??? { ????????? printf("打開(kāi)文件出錯(cuò)"); ????????? exit(1); ??? } ??? else ??? { ????????? printf("打開(kāi)(創(chuàng)建)文件“file”,文件描述符為:%d",fd); ??? } ??? if(close(fd)<0) ??? { ????????? printf("關(guān)閉文件出錯(cuò)"); ????????? exit(1); ??? } ??? system("ls /home/file -l"); ??? return 0; } open 函數(shù)的簡(jiǎn)單描述 #include?<fcntl.h> int open(const char *pathname, int oflag, ... /* mode_t mode */); 返回值:成功則返回文件描述符,否則返回 -1 對(duì)于 open 函數(shù)來(lái)說(shuō),第三個(gè)參數(shù)(...)僅當(dāng)創(chuàng)建新文件時(shí)才使用,用于指定文件的訪(fǎng)問(wèn)權(quán)限位(access permission bits)。pathname 是待打開(kāi)/創(chuàng)建文件的路徑名(如 C:/cpp/a.cpp);oflag 用于指定文件的打開(kāi)/創(chuàng)建模式,這個(gè)參數(shù)可由以下常量(定義于 fcntl.h)通過(guò)邏輯或構(gòu)成。 ????? O_RDONLY????? 只讀模式 ????? O_WRONLY????? 只寫(xiě)模式 ????? O_RDWR??????? 讀寫(xiě)模式 打開(kāi)/創(chuàng)建文件時(shí),至少得使用上述三個(gè)常量中的一個(gè)。以下常量是選用的: ????? O_APPEND?????? 每次寫(xiě)操作都寫(xiě)入文件的末尾 ? ????? O_CREAT??????? 如果指定文件不存在,則創(chuàng)建這個(gè)文件? ????? O_EXCL???????? 如果要?jiǎng)?chuàng)建的文件已存在,則返回 -1,并且修改 errno 的值 ????? O_TRUNC??????? 如果文件存在,并且以只寫(xiě)/讀寫(xiě)方式打開(kāi),則清空文件全部?jī)?nèi)容? ????? O_NOCTTY?????? 如果路徑名指向終端設(shè)備,不要把這個(gè)設(shè)備用作控制終端。 ????? O_NONBLOCK???? 如果路徑名指向 FIFO/塊文件/字符文件,則把文件的打開(kāi)和后繼 I/O設(shè)置為非阻塞模式(nonblocking mode) 以下三個(gè)常量同樣是選用的,它們用于同步輸入輸出 ????? O_DSYNC??????? 等待物理 I/O 結(jié)束后再 write。在不影響讀取新寫(xiě)入的數(shù)據(jù)的前提下,不等待文件屬性更新。 ????? O_RSYNC??????? read 等待所有寫(xiě)入同一區(qū)域的寫(xiě)操作完成后再進(jìn)行 ????? O_SYNC???????? 等待物理 I/O 結(jié)束后再 write,包括更新文件屬性的 I/O open 返回的文件描述符一定是最小的未被使用的描述符。 close函數(shù)說(shuō)明: 頭文件:#include?<unistd.h> 函數(shù)原型:int close(int filedes); 返回值:0(成功)或者 -1(出錯(cuò)) 進(jìn)程結(jié)束時(shí),該進(jìn)程打開(kāi)的所有文件都會(huì)自動(dòng)被內(nèi)核(kernel)關(guān)閉。 4.3 文件的讀寫(xiě) ?????當(dāng)文件按指定的工作方式打開(kāi)以后,就可以執(zhí)行對(duì)文件的讀和寫(xiě)。下面按文件的性質(zhì)分類(lèi)進(jìn)行操作。針對(duì)文本文件和二進(jìn)制文件的不同性質(zhì),對(duì)文本文件來(lái)說(shuō),可按字符讀寫(xiě)或按字符串讀寫(xiě);對(duì)二進(jìn)制文件來(lái)說(shuō),可進(jìn)行成塊的讀寫(xiě)或格式化的讀寫(xiě)。?下面是流文件的讀寫(xiě)操作。 1. 讀寫(xiě)字符 ??? C提供fgetc和fputc函數(shù)對(duì)文本文件進(jìn)行字符的讀寫(xiě),其函數(shù)的原型存于stdio.h頭文件中,格式為: ??? int fgetc(FILE *stream) ??? fgetc( )函數(shù)從輸入流的當(dāng)前位置返回一個(gè)字符,并將文件指針指示器移到下一個(gè)字符處,如果已到文件尾,函數(shù)返回EOF,此時(shí)表示本次操作結(jié)束,若讀寫(xiě)文件完成,則應(yīng)關(guān)閉文件。 ??? int fputc(int ch,FILE *stream) ??? fputc()函數(shù)完成將字符c h的值寫(xiě)入所指定的流文件的當(dāng)前位置處,并將文件指針后移一位。fputc()函數(shù)的返回值是所寫(xiě)入字符的值,出錯(cuò)時(shí)返回EOF 2. 讀寫(xiě)字符串 ??? C提供讀寫(xiě)字符串的函數(shù)原型在stdio.h頭文件中,其函數(shù)形式為: ??? Char *fgets(char *str,int num,FILE *stream) ??? fgets() 函數(shù)從流文件stream中讀取至多num-1個(gè)字符,并把它們放入str指向的字符數(shù)組中。讀取字符直到遇見(jiàn)回車(chē)符或E O F(文件結(jié)束符)為止,或讀入了所限定的字符數(shù)。 ??? int fputs(char *str,FILE *stream) ??? fputs( )函數(shù)將str指向的字符串寫(xiě)入流文件。操作成功時(shí),函數(shù)返回0值,失敗返回非零值 3. 格式化的讀寫(xiě) 前面的程序設(shè)計(jì)中,我們介紹過(guò)利用scanf( )和printf( )函數(shù)從鍵盤(pán)格式化輸入及在顯示器上進(jìn)行格式化輸出。對(duì)文件的格式化讀寫(xiě)就是在上述函數(shù)的前面加一個(gè)字母f成為fscanf( )和fprintf( )。其函數(shù)調(diào)用方式: int?fscanf(FILE *stream,char *format,arg_list) int?fprintf(FILE *stream,char *format,arg_list) 其中,stream為流文件指針,其余兩個(gè)參數(shù)與scanf( )和printf( )用法完全相同。 4. 成塊讀寫(xiě) 前面介紹的幾種讀寫(xiě)文件的方法,對(duì)其復(fù)雜的數(shù)據(jù)類(lèi)型無(wú)法以整體形式向文件寫(xiě)入或從文件讀出。C語(yǔ)言提供成塊的讀寫(xiě)方式來(lái)操作文件,使其數(shù)組或結(jié)構(gòu)體等類(lèi)型可以進(jìn)行一次性讀寫(xiě)。成塊讀寫(xiě)文件函數(shù)的調(diào)用形式為: int fread(void *buf,int size,int count,FILE *stream) int fwrite(void *buf,int size,int count,FILE *stream) fread()函數(shù)從stream 指向的流文件讀取count (字段數(shù))個(gè)字段,每個(gè)字段為size(字段長(zhǎng)度)個(gè)字符長(zhǎng),并把它們放到b u f(緩沖區(qū))指向的字符數(shù)組中。 fread()函數(shù)返回實(shí)際已讀取的字段數(shù)。若函數(shù)調(diào)用時(shí)要求讀取的字段數(shù)超過(guò)文件存放的字段數(shù),則出錯(cuò)或已到文件尾,實(shí)際在操作時(shí)應(yīng)注意檢測(cè)。 fwrite( )函數(shù)從buf(緩沖區(qū))指向的字符數(shù)組中,把count(字段數(shù))個(gè)字段寫(xiě)到stream所指向的流中,每個(gè)字段為size個(gè)字符長(zhǎng),函數(shù)操作成功時(shí)返回所寫(xiě)字段數(shù)。 關(guān)于成塊的文件讀寫(xiě),在創(chuàng)建文件時(shí)只能以二進(jìn)制文件格式創(chuàng)建。 ?????? 這些流文件的讀寫(xiě)操作我們?cè)贑語(yǔ)言中經(jīng)常用到,所以就不舉例子了,下面的是不帶緩存的文件讀寫(xiě),主要用到read函數(shù),write函數(shù)和lseek函數(shù)。read函數(shù)用于將指定的文件描述符中讀出數(shù)據(jù)。write函數(shù)用于向打開(kāi)的文件寫(xiě)數(shù)據(jù),寫(xiě)操作從文件當(dāng)前位置開(kāi)始。lseek函數(shù)用于在指定的文件描述符中將文件指針定位到相應(yīng)的位置。 1. read 頭文件:#include?<unistd.h> 函數(shù)原型:ssize_t read(int filedes, void *buf, size_t nbytes); 返回值:讀取到的字節(jié)數(shù);0(讀到 EOF);-1(出錯(cuò)) read 函數(shù)從 filedes 指定的已打開(kāi)文件中讀取 nbytes 字節(jié)到 buf 中。以下幾種情況會(huì)導(dǎo)致讀取到的字節(jié)數(shù)小于 nbytes : A. 讀取普通文件時(shí),讀到文件末尾還不夠 nbytes 字節(jié)。例如:如果文件只有 30 字節(jié),而我們想讀取 100 字節(jié),那么實(shí)際讀到的只有 30 字節(jié),read 函數(shù)返回 30 。此時(shí)再使用 read 函數(shù)作用于這個(gè)文件會(huì)導(dǎo)致 read 返回 0 。 B. 從終端設(shè)備(terminal device)讀取時(shí),一般情況下每次只能讀取一行 C. 從網(wǎng)絡(luò)讀取時(shí),網(wǎng)絡(luò)緩存可能導(dǎo)致讀取的字節(jié)數(shù)小于 nbytes 字節(jié)。 ?D. 讀取 pipe 或者 FIFO 時(shí),pipe 或 FIFO 里的字節(jié)數(shù)可能小于 nbytes 。 ?E. 從面向記錄(record-oriented)的設(shè)備讀取時(shí),某些面向記錄的設(shè)備(如磁帶)每次最多只能返回一個(gè)記錄。 ?F. 在讀取了部分?jǐn)?shù)據(jù)時(shí)被信號(hào)中斷。 讀操作始于 cfo 。在成功返回之前,cfo 增加,增量為實(shí)際讀取到的字節(jié)數(shù)。 2. write 頭文件:#include?<unistd.h> 函數(shù)原型:ssize_t write(int filedes, const void *buf, size_t nbytes) 返回值:寫(xiě)入文件的字節(jié)數(shù)(成功);-1(出錯(cuò)) write 函數(shù)向 filedes 中寫(xiě)入 nbytes 字節(jié)數(shù)據(jù),數(shù)據(jù)來(lái)源為 buf 。返回值一般總是等于 nbytes,否則就是出錯(cuò)了。常見(jiàn)的出錯(cuò)原因是磁盤(pán)空間滿(mǎn)了或者超過(guò)了文件大小限制。對(duì)于普通文件,寫(xiě)操作始于 cfo 。如果打開(kāi)文件時(shí)使用了 O_APPEND,則每次寫(xiě)操作都將數(shù)據(jù)寫(xiě)入文件末尾。成功寫(xiě)入后,cfo 增加,增量為實(shí)際寫(xiě)入的字節(jié)數(shù)。 例程:編寫(xiě)一個(gè)程序,在當(dāng)前目錄下創(chuàng)建用戶(hù)可讀寫(xiě)文件“hello.txt”,在其中寫(xiě)入“Hello, software weekly”,關(guān)閉該文件。再次打開(kāi)該文件,讀取其中的內(nèi)容并輸出在屏幕上 #include <cstring> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #define LENGTH 100 main() { int fd, len; char str[LENGTH]; fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 創(chuàng)建并打開(kāi)文件 */ if (fd) { write(fd, "Hello, Software Weekly", strlen("Hello, software weekly")); /* 寫(xiě)入 Hello, software weekly字符串 */ close(fd); } fd = open("hello.txt", O_RDWR); len = read(fd, str, LENGTH); /* 讀取文件內(nèi)容 */ str[len] = '\0'; printf("%s\n", str); close(fd); } 4.4 文件的上鎖 ????? Linux是多用戶(hù)操作系統(tǒng),多個(gè)用戶(hù)共同使用,操作同一個(gè)文件的事情很容易就發(fā)生。linux為了避免這種情況,就給這個(gè)文件上鎖,以避免共享資源產(chǎn)生競(jìng)爭(zhēng),導(dǎo)致數(shù)據(jù)讀寫(xiě)錯(cuò)誤。Linux中給文件上鎖主要有建議性鎖和強(qiáng)制性鎖。建議性鎖是這樣規(guī)定的:每個(gè)使用上鎖文件的進(jìn)程都要檢查是否有鎖存在,當(dāng)然還得尊重已有的鎖。內(nèi)核和系統(tǒng)總體上都堅(jiān)持不使用建議性鎖,它們依靠程序員遵守這個(gè)規(guī)定。強(qiáng)制性鎖是由內(nèi)核執(zhí)行的。當(dāng)文件被上鎖來(lái)進(jìn)行寫(xiě)入操作時(shí),在鎖定該文件的進(jìn)程釋放該鎖之前,內(nèi)核會(huì)阻止任何對(duì)該文件的讀或?qū)懺L(fǎng)問(wèn),每次讀或?qū)懺L(fǎng)問(wèn)都得檢查鎖是否存在。給文件加建議性鎖的是flock函數(shù),加強(qiáng)制性鎖的是fcntl函數(shù)。,一般情況下,系統(tǒng)使用強(qiáng)制性鎖,而很少使用建議性鎖。 fcntl()用來(lái)操作文件描述詞的一些特性。參數(shù)fd代表欲設(shè)置的文件描述詞,參數(shù)cmd代表欲操作的指令。文件描述詞,當(dāng)一個(gè)文件打開(kāi)后,系統(tǒng)會(huì)分配一部分資源來(lái)保存該文件的信息.以后對(duì)文件的操作就可以直接引用該部分資源了,文件描述詞可以認(rèn)為是該部分資源的一個(gè)索引,在打開(kāi)文件時(shí)返回.fcntl是用來(lái)對(duì)文件的一些屬性進(jìn)行設(shè)置的,需要一個(gè)文件描述詞參數(shù).有以下幾種情況: F_DUPFD用來(lái)查找大于或等于參數(shù)arg的最小且仍未使用的文件描述詞,并且復(fù)制參 數(shù)fd的文件描述詞。執(zhí)行成功則返回新復(fù)制的文件描述詞。請(qǐng)參考dup2()。F_GETFD取得close-on-exec旗標(biāo)。若此旗標(biāo)的 FD_CLOEXEC位為0,代表在調(diào)用exec()相關(guān)函數(shù)時(shí)文件將不會(huì)關(guān)閉。 F_SETFD 設(shè)置close-on-exec 旗標(biāo)。該旗標(biāo)以參數(shù)arg 的FD_CLOEXEC位決定。 F_GETFL 取得文件描述詞狀態(tài)旗標(biāo),此旗標(biāo)為open()的參數(shù)flags。 F_SETFL 設(shè)置文件描述詞狀態(tài)旗標(biāo),參數(shù)arg為新旗標(biāo),但只允許O_APPEND、O_NONBLOCK和O_ASYNC位的改變,其他位的改變將不受影響。 F_GETLK 取得文件鎖定的狀態(tài)。 F_SETLK 設(shè)置文件鎖定的狀態(tài)。此時(shí)flcok 結(jié)構(gòu)的l_type 值必須是F_RDLCK、F_WRLCK或F_UNLCK。如果無(wú)法建立鎖定,則返回-1,錯(cuò)誤代碼為EACCES 或EAGAIN。 F_SETLKW F_SETLK 作用相同,但是無(wú)法建立鎖定時(shí),此調(diào)用會(huì)一直等到鎖定動(dòng)作成功為止。若在等待鎖定的過(guò)程中被信號(hào)中斷時(shí),會(huì)立即返回-1,錯(cuò)誤代碼為EINTR。參數(shù)lock指針為flock 結(jié)構(gòu)指針,定義如下 struct flcok { short int l_type; /* 鎖定的狀態(tài)*/ short int l_whence;/*決定l_start位置*/ off_t l_start; /*鎖定區(qū)域的開(kāi)頭位置*/ off_t l_len; /*鎖定區(qū)域的大小*/ pid_t l_pid; /*鎖定動(dòng)作的進(jìn)程*/ }; l_type 有三種狀態(tài): F_RDLCK 建立一個(gè)供讀取用的鎖定 F_WRLCK 建立一個(gè)供寫(xiě)入用的鎖定 F_UNLCK 刪除之前建立的鎖定 l_whence 也有三種方式: SEEK_SET 以文件開(kāi)頭為鎖定的起始位置。 SEEK_CUR 以目前文件讀寫(xiě)位置為鎖定的起始位置 SEEK_END 以文件結(jié)尾為鎖定的起始位置。 返回值 成功則返回0,若有錯(cuò)誤則返回-1,錯(cuò)誤原因存于errno. 該函數(shù)可以改變已打開(kāi)的文件的性質(zhì)。 #include int fcntl(int fields, int cmd, .../* int arg */); //若成功則依賴(lài)于cmd,若出錯(cuò)則返回-1 第三個(gè)參數(shù)總是一個(gè)整數(shù),與上面所示函數(shù)原型中的注釋部分相對(duì)應(yīng)。但是在作為記錄鎖用時(shí),第三個(gè)參數(shù)則是指向一個(gè)結(jié)構(gòu)的指針。 fcntl函數(shù)有5種功能: 1.復(fù)制一個(gè)現(xiàn)有的描述符(cmd=F_DUPFD). 2.獲得/設(shè)置文件描述符標(biāo)記(cmd=F_GETFD或F_SETFD). 3.獲得/設(shè)置文件狀態(tài)標(biāo)記(cmd=F_GETFL或F_SETFL). 4.獲得/設(shè)置異步I/O所有權(quán)(cmd=F_GETOWN或F_SETOWN). 5.獲得/設(shè)置記錄鎖(cmd=F_GETLK,F_SETLK或F_SETLKW). 例子:打開(kāi)“/home/hubin”下的一個(gè)“file”文件,打開(kāi)后對(duì)其加上強(qiáng)制性的寫(xiě)入鎖,然后釋放寫(xiě)入鎖。程序源代碼見(jiàn)附件中的lock_set.c.編譯成功后,打開(kāi)兩個(gè)終端,都執(zhí)行l(wèi)ock_set,程序結(jié)果如下: 終端1: 加上寫(xiě)入鎖的是:7800 釋放強(qiáng)制性鎖:7800 終端2: 加上寫(xiě)入鎖的是:7800 加上寫(xiě)入鎖的是:7803 釋放強(qiáng)制性鎖:7803 由程序運(yùn)行結(jié)果可知,此程序在終端1中運(yùn)行后的第一個(gè)進(jìn)程,先打開(kāi)或創(chuàng)建文件"file",接著給“file”加上寫(xiě)入鎖,鎖定文件,并打印輸出加鎖信息和給文件加鎖進(jìn)程的進(jìn)程號(hào),這兒加的是“寫(xiě)入鎖”,這臺(tái)機(jī)器上第一個(gè)給文件加鎖進(jìn)程 的進(jìn)程號(hào)是“7800”,最后等待用戶(hù)按任意鍵后解除鎖定,并打印輸出解鎖信息和給文件解鎖進(jìn)程的進(jìn)程號(hào)。如果在第一個(gè)進(jìn)程解除鎖定前,此程序在另一個(gè)終端中在運(yùn)行,即運(yùn)行第二個(gè)進(jìn)程,此時(shí)文件已經(jīng)被第一進(jìn)程上鎖,那么第二個(gè)進(jìn)程無(wú)法上鎖,只能先打印輸出文件已經(jīng)上鎖和第一個(gè)進(jìn)程的進(jìn)程號(hào)的信息。直到前一個(gè)進(jìn)程解鎖后,后一個(gè)進(jìn)程才能上鎖,解鎖。 4.5 文件的定位 ????? 文件中有一個(gè)位置指針,指向當(dāng)前讀寫(xiě)的位置。如果順序讀寫(xiě)一個(gè)文件,每次讀寫(xiě)一個(gè)字符,則讀寫(xiě)完一個(gè)字符后,該位置指針自動(dòng)移動(dòng)指向下一個(gè)字符位置。當(dāng)需要改變文 件順序讀寫(xiě)的次序時(shí),根據(jù)需要隨時(shí)指定文件讀寫(xiě)的位置,也就是能實(shí)現(xiàn)文件的隨機(jī)讀寫(xiě)操作,這種功能是由 C 語(yǔ)言提供的文件定位函數(shù)來(lái)實(shí)現(xiàn)的。 文件的定位函數(shù)有l(wèi)seek,fseek,rewind,ftell等函數(shù)。其中l(wèi)seek是不帶緩存的文件操作,其他的是流文件操作。 4.5.1.lseek函數(shù) ????? 所有打開(kāi)的文件都有一個(gè)當(dāng)前文件偏移量(current file offset),以下簡(jiǎn)稱(chēng)為 cfo。cfo 通常是一個(gè)非負(fù)整數(shù),用于表明文件開(kāi)始處到文件當(dāng)前位置的字節(jié)數(shù)。讀寫(xiě)操作通常開(kāi)始于 cfo,并且使 cfo 增大,增量為讀寫(xiě)的字節(jié)數(shù)。文件被打開(kāi)時(shí),cfo 會(huì)被初始化為 0,除非使用了?O_APPEND?。使用 lseek 函數(shù)可以改變文件的 cfo 。函數(shù)說(shuō)明: 頭文件: #include?<unistd.h> 函數(shù)原型:off_t lseek(int filedes, off_t offset, int whence); 返回值:新的偏移量(成功),-1(失敗) 參數(shù) offset 的含義取決于參數(shù) whence: 1. 如果 whence 是?SEEK_SET,文件偏移量將被設(shè)置為 offset。 2. 如果 whence 是?SEEK_CUR,文件偏移量將被設(shè)置為 cfo 加上 offset,offset 可以為正也可以為負(fù)。 3. 如果 whence 是?SEEK_END,文件偏移量將被設(shè)置為文件長(zhǎng)度加上 offset,offset 可以為正也可以為負(fù)。 SEEK_SET、SEEK_CUR 和 SEEK_END 是 System V 引入的,在這之前使用的是 0、1 和 2。 lseek 的以下用法返回當(dāng)前的偏移量: off_t??? currpos; currpos = lseek(fd, 0, SEEK_CUR); 這個(gè)技巧也可用于判斷我們是否可以改變某個(gè)文件的偏移量。如果參數(shù) fd(文件描述符)指定的是 pipe(管道)、FIFO 或者 socket,lseek 返回 -1 并且置 errno 為?ESPIPE。對(duì)于普通文件(regular file),cfo 是一個(gè)非負(fù)整數(shù)。但對(duì)于特殊設(shè)備,cfo?有可能是負(fù)數(shù)。因此,我們不能簡(jiǎn)單地測(cè)試 lseek 的返回值是否小于 0 來(lái)判斷 lseek 成功與否,而應(yīng)該測(cè)試 lseek 的返回值是否等于 -1 來(lái)判斷 lseek 成功與否。lseek 僅將 cfo 保存于內(nèi)核中,不會(huì)導(dǎo)致任何 I/O 操作。這個(gè) cfo 將被用于之后的讀寫(xiě)操作。如果 offset 比文件的當(dāng)前長(zhǎng)度更大,下一個(gè)寫(xiě)操作就會(huì)把文件“撐大(extend)”。這就是所謂的在文件里創(chuàng)造“空洞(hole)”。沒(méi)有被實(shí)際寫(xiě)入文件的所有字節(jié)由重復(fù)的 0?表示。空洞是否占用硬盤(pán)空間是由文件系統(tǒng)(file system)決定的。例程: #include?<stdio.h> #include?<fcntl.h> #include?<unistd.h> #include?<sys/stat.h> ? char??? buf1[] = "abcdefghij";char??? buf2[] = "ABCDEFGHIJ"; int main(void) { ? ?? int? fd, size; ???? if ((fd = creat("file.hole", S_IRUSR|S_IWUSR)) < 0) ? ?? { ?????????? printf("creat error\n"); ?????????? return -1; ? ?? } ???? size = sizeof(buf1); ???? if (write(fd, buf1, size) != size) ???? {?????? ??????????? printf("buf1 write error\n"); ??????????? return -1; ???? } ???? /* offset now = 10 */ ???? if (lseek(fd, 16384, SEEK_SET) == -1) ???? { ? ? ? ? ?? printf("lseek error\n"); ?????????? return -1; ? ?? } ? ? ? /* offset now = 16384 */ ???? size = sizeof(buf2); ???? if (write(fd, buf2, size) != size) ???? { ??????????? printf("buf2 write error\n"); ??????????? return -1; ???? } ? ? ? /* offset now = 16394 */ ??? return 0; ? ? } 4.5.2 定位讀寫(xiě)指針函數(shù)fseek ( ) ????? 該函數(shù)的功能是將文件的讀寫(xiě)指針從某個(gè)位置移到指定的位置,該函數(shù)將為C語(yǔ)言對(duì)文件的隨機(jī)讀寫(xiě)提供了方法。該函數(shù)調(diào)用格式如下: fseek(fp, f<偏移量),(起始位置)) 其中,fseek是該函數(shù)的函數(shù)名;fp是指向被操作文件的文件指針;<偏移量)是表示移動(dòng)當(dāng)前讀寫(xiě)指針的距離量,該參數(shù)的類(lèi)型為long int型;<起始位置)是偏移量的相對(duì)位置。例如,起始位置為文件頭,偏移量為50,則表示將讀寫(xiě)指針移到相對(duì)文件頭距離為50個(gè)字節(jié)的位置。起始 位置的設(shè)置方法有三; ??? 0表示相對(duì)于文件頭 ??? 1表示相對(duì)于文件的當(dāng)前位置 ??? 2表示祖對(duì)于文件尾 ??? 實(shí)際中,常用宏定義來(lái)替代起始位置,規(guī)定如下: ??? SEEK_SE'C表示文件頭 ??? SEEK_CUR表示當(dāng)前位置 ??? SEEK_END表示文件尾 ??? 例如: ??? fseek(fp,200L,0);將讀寫(xiě)指針移到離文件頭20.個(gè)字節(jié)處。 ??? fseek(fp, 80L,1);將讀寫(xiě)指針移到離當(dāng)前位置80個(gè)字節(jié)處。 ??? fseek (fp , -50L,0);將讀寫(xiě)指針移到從文件尾向后退50個(gè)字節(jié)處。 ??? 該函數(shù)一般用于二進(jìn)制文件。如果用于文本文件要發(fā)生字符轉(zhuǎn)換,計(jì)算位置時(shí)會(huì)發(fā)生誤差。 4.5.3 歸位讀寫(xiě)指針函數(shù)rewind () ?????? 該函數(shù)的功能是將某個(gè)文件的讀寫(xiě)指針歸位于文件頭。該函數(shù)的調(diào)用格式如下: rewind(fp)其中,rewind是該函數(shù)的函數(shù)名,fp是被操作文件的文件指針。使用該函數(shù)后,會(huì)使被操作文件的讀寫(xiě)指針指向文件頭。該函數(shù)的功能與下列函數(shù)功能相同。 (seek (fp,OL.0); 4.5.4 返回讀寫(xiě)指針函數(shù)ftell ( ) ?????? 該函數(shù)的功能是返回指定文件當(dāng)前讀寫(xiě)指針的位置,該位置是用相對(duì)于文件頭所相隔的字節(jié)數(shù)來(lái)表示。例如,該函數(shù)返回某個(gè)文件的當(dāng)前讀寫(xiě)指針的位置是100字節(jié),即表示當(dāng)前讀寫(xiě)指針在離文件頭有100個(gè)字節(jié)處。該函數(shù)調(diào)用格式如下:ftell(fp)它返回一個(gè)表示字節(jié)數(shù)的long int型數(shù)值。 例程:建立一個(gè)數(shù)據(jù)文件,隨機(jī)讀取其中的某個(gè)數(shù)據(jù)。使用fprintf( )函數(shù)建立一個(gè)數(shù)據(jù)文件xy. dat ,然后,指定從某個(gè)數(shù)據(jù)起連續(xù)讀出若干個(gè)數(shù)據(jù),最后,再讀出這組數(shù)據(jù)的起始數(shù)據(jù)。程序內(nèi)容如下: #inciude <stdio.h> main ( ) { ????int i,x,y; ????FLLE * fp; ????fp=fopen("xy. dat" ,"wb十rb"); ????for (i=O;i<20;i++) ??????fprintf (fp,,%5d",i+1); ????printf("\nlnput x:"). ????scanf(^%d"&x), ????for(i=o;i<5:i十十) ????{ ??????fseek(fp, (long) (5*(x一l+i),0); ??????fscanf (fp ,"%d",&y); ??????printf("%d\t",y). ????} fseek(fp,(Iong)(5*x一5),0): fscan((fp,"%d",&c ), rewind(fp); printf("\n%d\n",&x); fclose(fp); 4.6 特殊文件的操作????? linux中,除了普通文件外,還有積累重要的特殊文件。特殊文件的操作和普通文件操作類(lèi)似,最常用的主要有目錄文件和鏈接文件。 4.6.1 目錄文件的操作 ????? 對(duì)目錄文件的操作可以使用mkdir函數(shù),opendir函數(shù),closedir函數(shù),readdir函數(shù)和scandir函數(shù)。例程:讀取系統(tǒng)目錄文件"/etc/rc.d"中的所有目錄結(jié)構(gòu)。 #include <cstring> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { ??? DIR *dir; ??? struct dirent *ptr; ??? int i; ??? dir=opendir("/etc/rc.d"); ??? while((ptr=readdir(dir))!=NULL) ????????? printf("目錄:%s\n",ptr->d_name); ??? closedir(dir); } opendir函數(shù)說(shuō)明: 所需頭文件:#include <sys/types.h> ?????????????????? #include <dirent.h> 函數(shù)功能:打開(kāi)目錄句柄 函數(shù)原型:DIR *opendir(const char *name); 函數(shù)傳入值:打開(kāi)參數(shù)name指定的目錄,并返回DIR *形態(tài)的目錄流,對(duì)目錄的讀取和搜索都要使用此返回值 函數(shù)返回值:成功則返回DIR *形態(tài)的目錄流,打開(kāi)失敗則返回NULL。 readdir函數(shù)說(shuō)明: 所需頭文件:#include <sys/types.h> ?????????????????? #include <sys/stat.h> ?????????????????? #include <fcntl.h> 函數(shù)功能:讀取目錄文件 函數(shù)原型:struct dirent *readdir(DIR *dir); 函數(shù)傳入值:返回參數(shù)dir目錄流的下個(gè)目錄進(jìn)入點(diǎn) ??????????????????? dirent結(jié)構(gòu)定義如下: ??????????????????? struct dirent ??????????????????? { ????????????????????????? ino_t d_ino; ????????????????????????? ff_t d_off; ????????????????????????? signed short int d_reclen; ????????????????????????? unsigned char d_type; ????????????????????????? har d_name[256]; ?????????????????? } ?????????????????? d_ino 此目錄進(jìn)入點(diǎn)的inode ?????????????????? d_off 目錄文件開(kāi)頭至此目錄進(jìn)入點(diǎn)的位移 ?????????????????? d_reclen_name的長(zhǎng)度,不包含NULL字符 ?????????????????? d_type d_name所指的文件類(lèi)型 ?????????????????? s_name 文件名 函數(shù)返回值:成功則返回下個(gè)目錄進(jìn)入點(diǎn),有錯(cuò)誤發(fā)生或讀取到目錄文件尾則返回NULL closedir函數(shù)說(shuō)明: 所需頭文件:#include <sys/types.h> ?????????????????? #include <dirent.h> 函數(shù)功能:關(guān)閉目錄文件 函數(shù)原型:int closedir(DIR *dir) 函數(shù)傳入值:參數(shù)dir:目錄流 函數(shù)返回值:關(guān)閉成功則返回0,失敗返回-1。 4.6.2 鏈接文件的操作 ?????? Linux系統(tǒng)中的鏈接文件,有點(diǎn)類(lèi)似于Windows系統(tǒng)中的“快捷方式”,但并不完全一樣,Linux系統(tǒng)中的鏈接方式有兩種:軟鏈接和硬鏈接。 1.軟鏈接文件 ????? 軟鏈接又叫符號(hào)鏈接,這個(gè)文件包含了另一個(gè)文件的路徑名。可以是任意文件或目錄,可以鏈接不同文件系統(tǒng)的文件。鏈接文件甚至可以鏈接不存在的文件,這就產(chǎn)生了一般稱(chēng)之為“斷鏈”的問(wèn)題,鏈接文件甚至可以循環(huán)鏈接自己,類(lèi)似于編程語(yǔ)言中的遞歸。例程:設(shè)計(jì)一個(gè)程序,要求為“/etc/passwd”文件建立軟鏈接“l(fā)ink”,并查看此鏈接文件和“/etc/passwd”文件。 #include <unistd.h> int main() { ??? symlink("/etc/passwd","link"); ??? system("ls link -l"); ??? system("ls /etc/passwd -l"); ??? return 0; } 程序運(yùn)行結(jié)果如下: hubin@hubin-desktop:~/linux_c$ ./slink lrwxrwxrwx 1 hubin hubin 11 2009-08-03 08:29 link -> /etc/passwd -rw-r--r-- 1 root root 1487 2009-04-23 17:57 /etc/passwd 從程序運(yùn)行結(jié)果看,在新創(chuàng)建的“l(fā)ink”文件代表權(quán)限的10個(gè)字符中,第一位是"l",而且最后顯“->/etc/passwd”,表明鏈接目標(biāo)是"/etc/passwd"文件。 symlink函數(shù)說(shuō)明: 所需頭文件:#include <unistd.h> 函數(shù)功能:建立軟鏈接 函數(shù)原型:int symlink(const char *oldpath,const char *newpath); 函數(shù)傳入值:參數(shù)newpath:鏈接名稱(chēng) ??????????????????? 參數(shù)oldpath:已存在文件路徑或文件名 函數(shù)返回值:成功返回0,失敗返回-1 2. 硬鏈接文件 ?????? 對(duì)硬鏈接文件進(jìn)行讀寫(xiě)和刪除操作時(shí)候,結(jié)果和軟鏈接相同。但如果刪除硬鏈接文件的源文件,硬鏈接文件依然存在,而且保留了原有的內(nèi)容,只是,系統(tǒng)就“忘記了”它曾經(jīng)是硬鏈接文件,而把它當(dāng)成一個(gè)普通文件。硬鏈接文件有兩個(gè)限制:1).不允許給目錄創(chuàng)建硬鏈接;2).只有在同一文件系統(tǒng)中的文件之間才能創(chuàng)建鏈接。 ?????? 例程:設(shè)計(jì)一個(gè)程序,為“/etc/passwd”文件建立硬鏈接文件“hpasswd”,并查看此鏈接文件和“/etc/passwd”文件。 #include <unistd.h> int main() { ??? link("/etc/passwd","hardlink"); ??? system("ls hardlink -l"); ??? system("ls /etc/passwd -l"); ??? return 0; } 程序運(yùn)行結(jié)果: -rw-r--r-- 1 hubin hubin 0 2009-08-03 08:49 hardlink -rw-r--r-- 1 root root 1487 2009-04-23 17:57 /etc/passwd ? ? ? 從程序結(jié)果看,兩個(gè)文件表面上是一樣的,除了文件名,新建立的文件跟原文件顯示的屬性一模一樣,而且第二項(xiàng)是“1”,因此,確實(shí)建立了一個(gè)硬鏈接文件。 link函數(shù)說(shuō)明: 所需頭文件:#include <unistd.h> 函數(shù)功能:建立硬鏈接 函數(shù)原型:int link(const char *oldpath,const char *newpath); 函數(shù)傳入值:參數(shù)newpath:鏈接名稱(chēng) ??????????????????? 參數(shù)oldpath:已存在文件路徑或文件名 函數(shù)返回值:成功返回0,失敗返回-1 備注:如果參數(shù)newpath指定的名稱(chēng)為一不存在的文件,則不會(huì)建立鏈接。? 5.部分函數(shù)說(shuō)明 chmod?--?改變文件模式 說(shuō)明bool?chmod?( string filename, int mode)嘗試將?filename?所指定文件的模式改成?mode?所給定的。注意?mode?不會(huì)被自動(dòng)當(dāng)成八進(jìn)制數(shù)值,而且也不能用字符串(例如 "g+w")。要確保正確操作,需要給?mode?前面加上 0: |
?
總結(jié)
以上是生活随笔為你收集整理的linux gcc编译下的文件读写操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 十六、Python操作excel(.xl
- 下一篇: 安卓安装kali linux之Termu