Linux系统编程2.文件
生活随笔
收集整理的這篇文章主要介紹了
Linux系统编程2.文件
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. 文件讀寫和創建
標準文件操作函數:fopen、fread、fwrite等。
系統調用open函數打開一個文件進行操作,使用完成后調用close函數進行關閉。
#include <fcntl.h>; #include <unistd.h>; #include <sys/types.h>; #include <sys/stat.h>; int open(const char *pathname,int flags); //pathname 打開的文件名(包含路徑名稱,缺省:在當前路徑下面). //flags 可以去下面的一個值或者是幾個值的組合./* (前三個標志是唯一標志只能用一個)O_RDONLY:以只讀的方式打開文件.O_WRONLY:以只寫的方式打開文件.O_RDWR:以讀寫的方式打開文件.O_APPEND:以追加的方式打開文件.O_CREAT:創建一個文件.O_EXEC:如果使用了 O_CREAT 而且文件已經存在,就會發生一個錯誤.O_NOBLOCK:以非阻塞的方式打開一個文件.O_TRUNC:如果文件已經存在,則刪除文件的內容. */int open(const char *pathname,int flags,mode_t mode); /*如果使用了 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------------------------------------------------------- */ int close(int fd); >我們也可以用數字來代表各個位的標志.Linux 總共用 5 個數字來表示文件的各種權限. 00000.第一位表示設置用戶 ID.第二位表示設置組 ID,第三位表示用戶自己的權限位,第四Linux 操作系統位表示組的權限,最后一位表示其他人的權限. 每個數字可以取 1(執行權限),2(寫權限),4(讀權限),0(什么也沒有)或者是這幾個值的和 >>比如:創建一個用戶讀寫執行,組沒有權限,其他人讀執行的文件.設置用戶 ID 位那么 我們可以使用的模式是–1(設置用戶 ID)0(組沒有設置)7(1+2+4)0(沒有權限,使用缺省) 5(1+4)即 10705: >>open(“temp”,O_CREAT,10705); 打開文件成功,open 會返回一個文件描述符,對文件的所有操作就可以通過 對這個文件描述符進行操作了 文件打開了以后,就要對文件進行讀寫了,可以調用函數 read 和 write 進行文件的 讀寫。 #include <unistd.h>; ssize_t read(int fd, void *buffer,size_t count); ssize_t write(int fd, const void *buffer,size_t count); /*fd 行讀寫操作的文件描述符,buffer 寫入文件內容或讀出文件內容存放的內存地址.count 要讀寫的字節數. */ 實例: #include <unistd.h>; #include <fcntl.h>; #include <stdio.h>; #include <sys/types.h>; #include <sys/stat.h>; #include <errno.h>; #include <string.h>; #define BUFFER_SIZE 1024 int main(int argc,char **argv) {int from_fd,to_fd;int bytes_read,bytes_write;char buffer[BUFFER_SIZE];char *ptr;if(argc!=3){fprintf(stderr,"Usage: %s fromfile tofile\n\a",argv[0]);exit(1);} /* 打開源文件 */if((from_fd=open(argv[1],O_RDONLY))==-1){fprintf(stderr,"Open %s Error: %s\n",argv[1],strerror(errno));exit(1);}/* 創建目的文件 */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));exit(1);}/* 以下代碼是一個經典的拷貝文件的代碼 */while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)){/* 讀發生錯誤 */if((bytes_read==-1)&&(errno!=EINTR)) break;else if(bytes_read>0){ptr=buffer;while(bytes_write=write(to_fd,ptr,bytes_read)){/* 寫發生錯誤 */if((bytes_write==-1)&&(errno!=EINTR))break;/* 寫完了所有讀的字節 */else if(bytes_write==bytes_read) break;/* 只寫了一部分,繼續寫 */else if(bytes_write>0){ptr+=bytes_write;bytes_read-=bytes_write;}}/* 寫字節發生錯誤 */if(bytes_write==-1)break;}}close(from_fd);close(to_fd);exit(0); }2. 文件的各個屬性
文件具有各種各樣的屬性,除了文件的權限,還有創建時間,大小等屬性。
判斷文件是否可以進行某種操作(讀、寫等)。使用access函數。
int access(const char *pathname,int mode) /*pathname:文件名稱,mode :判斷的屬性.可以取R_OK 文件可以讀,W_OK 文件可以寫,X_OK 文件可以執行,F_OK 文件存在.或者是他們的組合.成功時 ,函數返回 0,否則如果有一個條件不符時,返回-1. */ 如果我們要獲得文件的其他屬性,我們可以使用函數 stat 或者 fstat。 #include <unistd.h>; int stat(const char *file_name,struct stat *buf); //stat 用來判斷沒有打開的文件 int fstat(int filedes,struct stat *buf); //fstat 用來判斷打開的文件struct stat {dev_t st_dev; /* 設備 */ino_t st_ino; /* 節點 */mode_t st_mode; /* 模式 */nlink_t st_nlink; /* 硬連接 */uid_t st_uid; /* 用戶 ID */gid_t st_gid; /* 組 ID */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; /* 最后一次改變時間(指屬性) */ };使用最多的屬性是 st_mode,通過st_mode屬性可以判斷給定的文件是一個普通文件還是一個目錄,連接等等.可以 使用下面幾個宏來判斷.
S_ISREG 是否是一個常規文件. S_ISDIR 是否是一個目錄 . S_ISCHR 是否是一個字符設備. S_ISBLK 是否是一個塊設備 . S_ISFIFO 是否 是一個 FIFO文件. S_ISSOCK 是否是一個 SOCKET 文件.3. 目錄文件的操作
c庫函數提供了getcwd來獲取當前工作路徑。
#include <unistd.h>; char *getcwd(char *buffer,size_t size); /*提供一個 size 大小的 buffer,getcwd 會把我們當前的路徑考到 buffer 中.如果 buffer太小,函數會返回-1 和一個錯誤號.*/Linux提供了大量目錄操作函數,以下是常用的
#include <dirent.h>; #include <unistd.h>; #include <fcntl.h>; #include <sys/types.h>; #include <sys/stat.h>; int mkdir(const char *path,mode_t mode); /*創建一個目錄*/ DIR *opendir(const char *path); /*打開一個目錄*/ struct dirent *readdir(DIR *dir); /*讀一個打開的目錄*/ void rewinddir(DIR *dir); /*重讀目錄*/ off_t telldir(DIR *dir); void seekdir(DIR *dir,off_t off); /*telldir 和 seekdir 類似與 ftee 和 fseek 函數*/ int closedir(DIR *dir); /*關閉目錄*/ struct dirent {long d_ino;off_t d_off;unsigned short d_reclen;char d_name[NAME_MAX+1]; /* 文件名稱 */}下面有一個實例,這個實例有一個參數。如果這個參數是一個文件名,我們輸出這個文件的大小和最后修改的時間,如果是一個目錄我們輸出這個目錄下所有文件的大小和修改時間。
#include <unistd.h>; #include <stdio.h>; #include <errno.h>; #include <sys/types.h>; #include <sys/stat.h>; #include <dirent.h>; #include <time.h>; static int get_file_size_time(const char *filename) {struct stat statbuf;if(stat(filename,&statbuf)==-1)/*獲取文件屬性失敗,返回-1*/{printf("Get stat on %s Error: %s\n",filename,strerror(errno));return(-1);}if(S_ISDIR(statbuf.st_mode))/*是一個目錄,返回1*/return(1);if(S_ISREG(statbuf.st_mode))/*是一個文件,打印文件大小,返回0*/printf("文件: %s 大小: %ld bytes\t修改時間: %s", filename,statbuf.st_size,ctime(&statbuf.st_mtime));return(0); } int main(int argc,char **argv)/*argc是參數個數+1 argv存放參數字符串,第一個參數字符串是命令名*/ {DIR *dirp;struct dirent *direntp;int stats;if(argc!=2)/*參數數目不對,報錯*/{printf("Usage: %s filename\n\a",argv[0]);exit(1);}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));exit(1);}while((direntp=readdir(dirp))!=NULL)/*循環讀直到空*/if(get_file_size_time(direntp->d_name)==-1)/*讀出錯,停止讀*/break;closedir(dirp);exit(1); }4. 管道文件
Linux提供了許多過濾和重定向程序,比如more cat等,還提供了’<’ ‘>’ ‘|’ ‘<<’ ‘>>’等重定向操作符。在這些重定向程序和操作符中都用到了管道這種特殊文件,系統調用pipe創建一個管道。
#include<unistd.h>; int pipe(int fildes[2]); /* pipe 調用可以創建一個管道(通信緩沖區).當調用成功時,可以訪問文件描述符 fildes[0],fildes[1].其中 fildes[0]是用來讀的文件描述符,而 fildes[1]是用來寫的文件描述符. */在實際使用中通過創建一個子進程,然后一個進程寫,一個進程讀來使用的。
實例:
#include <stdio.h>; #include <stdlib.h>; #include <unistd.h>; #include <string.h>; #include <errno.h>; #include <sys/types.h>; #include <sys/wait.h>; #define BUFFER 255 int main(int argc,char **argv) {char buffer[BUFFER+1];int fd[2];if(argc!=2)/*參數數目錯誤*/{fprintf(stderr,"Usage: %s string\n\a",argv[0]);exit(1);}if(pipe(fd)!=0)/*創建管道文件失敗*/{fprintf(stderr,"Pipe Error:%s\n\a",strerror(errno));exit(1);}if(fork()==0)/*子進程*/{close(fd[0]);/*關閉文件1*/printf("Child[%d] Write to pipe\n\a",getpid());snprintf(buffer,BUFFER,"%s",argv[1]);write(fd[1],buffer,strlen(buffer));/*buffer中內容寫入文件2*/printf("Child[%d] Quit\n\a",getpid());exit(0);}else/*不是子進程*/{close(fd[1]);/*關閉文件2*/printf("Parent[%d] Read from pipe\n\a",getpid());memset(buffer,'\0',BUFFER+1);/*buffer[BUFFER+1] = '/0' */read(fd[0],buffer,BUFFER);/*讀文件1到buffer*/printf("Parent[%d] Read: %s\n",getpid(),buffer);exit(1);} }為了實現重定向需要調用
#include <unistd.h>; int dup2(int oldfd,int newfd); /*dup2 將用 oldfd 文件描述符來代替 newfd 文件描述符,同時關閉 newfd文件描述符.也就是說,所有向 newfd 操作都轉到 oldfd 上面 */實例:(標準輸出重定向到一個文件)
#include <unistd.h>; #include <stdio.h>; #include <errno.h>; #include <fcntl.h>; #include <string.h>; #include <sys/types.h>; #include <sys/stat.h>; #define BUFFER_SIZE 1024 int main(int argc,char **argv) {int fd;char buffer[BUFFER_SIZE];if(argc!=2)/*參數錯誤*/{fprintf(stderr,"Usage: %s outfilename\n\a",argv[0]);exit(1);}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));exit(1);}if(dup2(fd,STDOUT_FILENO)==-1)/*重定向失敗*/{fprintf(stderr,"Redirect Standard Out Error: %s\n\a",strerror(errno));exit(1);}fprintf(stderr,"Now,please input string");fprintf(stderr,"(To quit use CTRL+D)\n");while(1){fgets(buffer,BUFFER_SIZE,stdin);/*從stdin讀入buffer*/if(feof(stdin))/*讀到stdin*/break;write(STDOUT_FILENO,buffer,strlen(buffer));/*寫入STDOUT_FILENO(STDOUT_FILENO已經被重定向)*/}exit(0); }總結
以上是生活随笔為你收集整理的Linux系统编程2.文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 压缩包加密、解密
- 下一篇: 谈谈mysql的悲观和乐观锁 - 周伯通