生活随笔
收集整理的這篇文章主要介紹了
Linux下文件的操作
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Linux下文件的操作 |
01-7-27 上午 10:34:05
|
| 我們在這一節將要討論linux下文件操作的各個函數。 |
| 我假設你已經知道了標準級的文件操作的各個函數(fopen,fread,fwrite等等)。當然如果你不清楚的話也不要著急。我們討論的系統級的文件操作實際上是為標準級文件操作服務的。 |
| 當我們需要打開一個文件進行讀寫操作的時候,我們可以使用系統調用函數open。使用完成以后我們調用另外一個close函數進行關閉操作。 |
| int open(const char *pathname,int flags); |
| int open(const char *pathname,int flags,mode_t mode); |
| open函數有兩個形式。其中pathname是我們要打開的文件名(包含路徑名稱,缺省是認為在當前路徑下面)。flags可以去下面的一個值或者是幾個值的組合。 |
| O_EXEC:如果使用了O_CREAT而且文件已經存在,就會發生一個錯誤。 |
| O_TRUNC:如果文件已經存在,則刪除文件的內容。 |
| 前面三個標志只能使用任意的一個。如果使用了O_CREATE標志,那么我們要使用open的第二種形式。還要指定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_IRWXO 其他人可以讀寫執行 |
| ----------------------------------------------------------------- |
| S_ISUID 設置用戶執行ID S_ISGID 設置組的執行ID |
| ----------------------------------------------------------------- |
| 我們也可以用數字來代表各個位的標志。Linux總共用5個數字來表示文件的各種權限。 |
| 00000。第一位表示設置用戶ID。第二位表示設置組ID,第三位表示用戶自己的權限位,第四位表示組的權限,最后一位表示其他人的權限。 |
| 每個數字可以取1(執行權限),2(寫權限),4(讀權限),0(什么也沒有)或者是這幾個值的和。 |
| 比如我們要創建一個用戶讀寫執行,組沒有權限,其他人讀執行的文件。設置用戶ID位那么我們可以使用的模式是--1(設置用戶ID)0(組沒有設置)7(1+2+4)0(沒有權限,使用缺省)5(1+4)即10705: |
| open("temp",O_CREAT,10705); |
| 如果我們打開文件成功,open會返回一個文件描述符。我們以后對文件的所有操作就可以對這個文件描述符進行操作了。 |
| 當我們操作完成以后,我們要關閉文件了,只要調用close就可以了,其中fd是我們要關閉的文件描述符。 |
| 文件打開了以后,我們就要對文件進行讀寫了。我們可以調用函數read和write進行文件的讀寫。 |
| ssize_t read(int fd, void *buffer,size_t count); |
| ssize_t write(int fd, const void *buffer,size_t count); |
| fd是我們要進行讀寫操作的文件描述符,buffer是我們要寫入文件內容或讀出文件內容的內存地址。count是我們要讀寫的字節數。 |
| 對于普通的文件read從指定的文件(fd)中讀取count字節到buffer緩沖區中(記住我們必須提供一個足夠大的緩沖區),同時返回count。 |
| 如果read讀到了文件的結尾或者被一個信號所中斷,返回值會小于count。如果是由信號中斷引起返回,而且沒有返回數據,read會返回-1,且設置errno為EINTR。當程序讀到了文件結尾的時候,read會返回0。 |
| write從buffer中寫count字節到文件fd中,成功時返回實際所寫的字節數。 |
| int main(int argc,char **argv) |
| int bytes_read,bytes_write; |
| char buffer[BUFFER_SIZE]; |
| fprintf(stderr,"Usage:%s fromfile tofile/n/a",argv[0]); |
| if((from_fd=open(argv[1],O_RDONLY))==-1) |
| fprintf(stderr,"Open %s Error:%s/n",argv[1],strerror(errno)); |
| if((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1) |
| fprintf(stderr,"Open %s Error:%s/n",argv[2],strerror(errno)); |
| while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)) |
| if((bytes_read==-1)&&(errno!=EINTR)) break; |
| while(bytes_write=write(to_fd,ptr,bytes_read)) |
| if((bytes_write==-1)&&(errno!=EINTR))break; |
| else if(bytes_write==bytes_read) break; |
| if(bytes_write==-1)break; |
| 文件具有各種各樣的屬性,除了我們上面所知道的文件權限以外,文件還有創建時間,大小等等屬性。 |
| 有時侯我們要判斷文件是否可以進行某種操作(讀,寫等等)。這個時候我們可以使用access函數。 |
| int access(const char *pathname,int mode); |
| pathname:是文件名稱,mode是我們要判斷的屬性??梢匀∫韵轮祷蛘呤撬麄兊慕M合。 |
| R_OK文件可以讀,W_OK文件可以寫,X_OK文件可以執行,F_OK文件存在。當我們測試成功時,函數返回0,否則如果有一個條件不符時,返回-1。 |
| 如果我們要獲得文件的其他屬性,我們可以使用函數stat或者fstat。 |
| int stat(const char *file_name,struct stat *buf); |
| int fstat(int filedes,struct stat *buf); |
| nlink_t st_nlink; /* 硬連接 */ |
| dev_t st_rdev; /* 設備類型 */ |
| off_t st_off; /* 文件字節數 */ |
| unsigned long st_blksize; /* 塊大小 */ |
| unsigned long st_blocks; /* 塊數 */ |
| time_t st_atime; /* 最后一次訪問時間 */ |
| time_t st_mtime; /* 最后一次修改時間 */ |
| time_t st_ctime; /* 最后一次改變時間(指屬性) */ |
| stat用來判斷沒有打開的文件,而fstat用來判斷打開的文件。我們使用最多的屬性是st_mode。通過著屬性我們可以判斷給定的文件是一個普通文件還是一個目錄,連接等等??梢允褂孟旅鎺讉€宏來判斷。 |
| S_ISLNK(st_mode):是否是一個連接。S_ISREG是否是一個常規文件。S_ISDIR是否是一個目錄S_ISCHR是否是一個字符設備。S_ISBLK是否是一個塊設備S_ISFIFO是否 是一個FIFO文件。S_ISSOCK是否是一個SOCKET文件。 我們會在下面說明如何使用這幾個宏的。 |
| 在我們編寫程序的時候,有時候會要得到我們當前的工作路徑。C庫函數提供了getcwd來解決這個問題。 |
| char *getcwd(char *buffer,size_t size); |
| 我們提供一個size大小的buffer,getcwd會把我們當前的路徑考到buffer中。如果buffer太小,函數會返回-1和一個錯誤號。 |
| Linux提供了大量的目錄操作函數,我們學習幾個比較簡單和常用的函數。 |
| int mkdir(const char *path,mode_t mode); |
| DIR *opendir(const char *path); |
| struct dirent *readdir(DIR *dir); |
| void rewinddir(DIR *dir); |
| void seekdir(DIR *dir,off_t off); |
| char d_name[NAME_MAX+1]; /* 文件名稱 */ |
| mkdir很容易就是我們創建一個目錄,opendir打開一個目錄為以后讀做準備。readdir讀一個打開的目錄。rewinddir是用來重讀目錄的和我們學的rewind函數一樣。closedir是關閉一個目錄。telldir和seekdir類似與ftee和fseek函數。 |
| 下面我們開發一個小程序,這個程序有一個參數。如果這個參數是一個文件名,我們輸出這個文件的大小和最后修改的時間,如果是一個目錄我們輸出這個目錄下所有文件的大小和修改時間。 |
| static int get_file_size_time(const char *filename) |
| if(stat(filename,&statbuf)==-1) |
| printf("Get stat on %s Error:%s/n", |
| filename,strerror(errno)); |
| if(S_ISDIR(statbuf.st_mode))return(1); |
| if(S_ISREG(statbuf.st_mode)) |
| printf("%s size:%ld bytes/tmodified at %s", |
| filename,statbuf.st_size,ctime(&statbuf.st_mtime)); |
| int main(int argc,char **argv) |
| printf("Usage:%s filename/n/a",argv[0]); |
| if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))exit(1); |
| if((dirp=opendir(argv[1]))==NULL) |
| printf("Open Directory %s Error:%s/n", |
| argv[1],strerror(errno)); |
| while((direntp=readdir(dirp))!=NULL) |
| if(get_file_size_time(direntp- |
| Linux提供了許多的過濾和重定向程序,比如more cat |
| 等等。還提供了< > | <<等等重定向操作符。在這些過濾和重 定向程序當中,都用到了管道這種特殊的文件。系統調用pipe可以創建一個管道。 |
| pipe調用可以創建一個管道(通信緩沖區)。當調用成功時,我們可以訪問文件描述符fildes[0],fildes[1]。其中fildes[0]是用來讀的文件描述符,而fildes[1]是用來寫的文件描述符。 |
| 在實際使用中我們是通過創建一個子進程,然后一個進程寫,一個進程讀來使用的。 |
| int main(int argc,char **argv) |
| fprintf(stderr,"Usage:%s string/n/a",argv[0]); |
| fprintf(stderr,"Pipe Error:%s/n/a",strerror(errno)); |
| printf("Child[%d] Write to pipe/n/a",getpid()); |
| snprintf(buffer,BUFFER,"%s",argv[1]); |
| write(fd[1],buffer,strlen(buffer)); |
| printf("Child[%d] Quit/n/a",getpid()); |
| printf("Parent[%d] Read from pipe/n/a",getpid()); |
| memset(buffer,'/0',BUFFER+1); |
| read(fd[0],buffer,BUFFER); |
| printf("Parent[%d] Read:%s/n",getpid(),buffer); |
| 為了實現重定向操作,我們需要調用另外一個函數dup2。 |
| int dup2(int oldfd,int newfd); |
| dup2將用oldfd文件描述符來代替newfd文件描述符,同時關閉newfd文件描述符。也就是說, |
| 所有向newfd操作都轉到oldfd上面。下面我們學習一個例子,這個例子將標準輸出重定向到一個文件。 |
| int main(int argc,char **argv) |
| char buffer[BUFFER_SIZE]; |
| fprintf(stderr,"Usage:%s outfilename/n/a",argv[0]); |
| if((fd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1) |
| fprintf(stderr,"Open %s Error:%s/n/a",argv[1],strerror(errno)); |
| if(dup2(fd,STDOUT_FILENO)==-1) |
| fprintf(stderr,"Redirect Standard Out Error:%s/n/a",strerror(errno)); |
| fprintf(stderr,"Now,please input string"); |
| fprintf(stderr,"(To quit use CTRL+D)/n"); |
| fgets(buffer,BUFFER_SIZE,stdin); |
| write(STDOUT_FILENO,buffer,strlen(buffer)); |
| 好了,文件一章我們就暫時先討論到這里,學習好了文件的操作我們其實已經可以寫出一些比較有用的程序了。我們可以編寫一個實現例如dir,mkdir,cp,mv等等常用的文件操作命令了。 |
總結
以上是生活随笔為你收集整理的Linux下文件的操作的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。