Linux文件I/O(6.1)
来源:互联网 发布:mysql 多字段distinct 编辑:程序博客网 时间:2024/06/10 02:38
/*------IO-day 2--------------------------------------*/Unix文件基础
一、出错处理:全局错误码errno /*{{{*/
函数出错会置errno,调用者根据errno的不同值可判断出错原因
使用时需要 errno.h 头文件
strerror() - 映射errno对应的错误信息
perror() – 输出用户信息及errno对应的错误信息
注意:只有当调用函数出错才需要检查errno/*}}}*/
二、系统调用及库函数
三、文件IO基础
文件IO :由Unix或linux操作系统内核实现(系统调用中文件操作)相应函数,并提供给应用层调用,实现文件操作,并且不带缓冲/*{{{*/
文件IO中操作对象 : 文件描述符 非负整数,内核用于区分和标识运行的程序中打开的文件
文件IO:不带缓冲 通过 文件描述符 进行访问 open()/read()/write()/lseek()/close()
标准IO:带缓冲 通过 流指针FILE* 进行访问 printf()/fprintf()/fopen()/fread()/fwrite()/fseek()/fclose()
/*}}}*/
文件操作:
一、文件IO相关函数
1.打开文件
//需头文件/*{{{*/#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);//功能:打开一个pathname指定的文件,由flags指定打开方式和权限,获得文件描述符参数:
pathname 打开文件的路径 "/home/will/test.txt" argv[1]
flags 打开方式
O_RDONLY O_WRONLY O_RDWR 三者选一
O_CREAT 文件不存在创建新文件,还需指定新建文件的权限mode
O_TRUNC 文件存在则截短为0
O_APPEND 每次都以追加方式写
O_EXCL 和O_CREAT 一起使用可测试文件是否存在,存在会出错EEXIST
注意:
1.这些宏可以用 | 连接
2.如果有O_CREAT标志,则需第三个参数mode指定新文件权限
mode 指定新建文件权限
注意:实际权限为mode & ~umask
返回值:成功返回当前未使用的最小的文件描述符;失败,返回-1,并置errno
//例:open("/home/will/test.txt",O_RDWR);open(argv[1],O_WRONLY | O_CREAT | O_TRUNC,0666);"r" --> O_RDONLY "r+" --> O_RDWR"w" --> O_WRONLY | O_TRUNC | O_CREAT,0666 "w+" --> O_RDWR | O_TRUNC | O_CREAT,0666 "a" --> O_WRONLY | O_APPEND | O_CREAT,0666 "a+" --> O_RDWR | O_APPEND | O_CREAT,0666练习:用类似标准IO fopen函数的"w"方式, 打开一个新文件
查看该文件的权限
#include <head.h>int main(int argc, const char *argv[]){int fd_s;if(argc != 2){fprintf(stderr,"usage : %s filename\n",argv[0]);return -1;}if((fd_s = open(argv[1],O_WRONLY | O_CREAT | O_TRUNC,0666)) == -1){perror("error");return -1;}return 0;}2.关闭文件
#include <unistd.h>/*{{{*/int close(int fd);功能:关闭打开文件
返回值:成功返回0;出错返回-1,并设置errno/*}}}*
3.读写文件
#include <unistd.h>/*{{{*/
1)读
ssize_t read(int fd, void *buf, size_t count);功能:从指定文件读指定个数字节
参数:
fd 指定读的文件
buf 读入数据存入内存区域首地址
count 指定读入字符个数
返回值 :成功,返回读入的字节数,0表示读到文件末尾;失败,返回-1,并置errno
例:
char buf[100];n = read(fd,buf,sizeof(buf));
ssize_t write(int fd, const void *buf, size_t count);功能:向指定文件写入指定个数字节
参数:
fd 指定写的文件
buf 写入数据存在内存区域首地址
count 指定写入字符个数
返回值:成功,返回写入的字节数,0表示一个都未写入;失败,返回-1,并置errno
例:
write(fd,buf,n);注意:读写都会影响文件表项中的offset,读写完后offset会相应增加有效读写字节数
练习:用read()/write()实现文件拷贝
#include <stdio.h>void do_copy(FILE *fp_s,FILE *fp_d){ int c; while((c = fgetc(fp_s)) != EOF) fputc(c,fp_d); return; }void do_copy_line(FILE *fp_s,FILE *fp_d){ char buf[100]; while((fgets(buf,sizeof(buf),fp_s)) != NULL) fputs(buf,fp_d); return; }void do_copy_obj(FILE *fp_s,FILE *fp_d){ char buf[100]; long n = 0; int cnt = 0; // 获得原文件的大小 fseek(fp_s,0,SEEK_END); n = ftell(fp_s); printf("src length = %ld\n",n); //创建空洞文件 fseek(fp_d,n-1,SEEK_SET); fprintf(fp_d," "); // getchar(); //定位到文件头 rewind(fp_s); rewind(fp_d); while((cnt = fread(buf,sizeof(char),sizeof(buf),fp_s)) != 0) fwrite(buf,sizeof(char),cnt,fp_d); return; }// ./a.out src destint main(int argc, const char *argv[]){ FILE *fp_s = NULL; FILE *fp_d = NULL; if( argc != 3) { fprintf(stdout,"Usage:%s src dest\n",argv[0]); return -1; } // open src file if((fp_s = fopen(argv[1],"r") ) == NULL) { perror("fopen"); return -1; } // open dest file if((fp_d = fopen(argv[2],"w") ) == NULL) { perror("fopen"); return -1; } //loop read write //do_copy_line(fp_s,fp_d); do_copy_obj(fp_s,fp_d); //close fclose(fp_s); fclose(fp_d); return 0;}4.定位文件
#include <sys/types.h>/*{{{*/#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);功能:在打开文件中修改当前文件位置指示器的值
参数:
fd 指定要定位的文件
offset 相对偏移量offset > 0,从起点whence向后偏移;offset < 0,从起点whence向前偏移
whence 相对偏移量起点
以下三个宏可选
SEEK_SET 文件开头,offset 只能取正值
SEEK_CUR 文件位置指示器当前位置,offset可正可负
SEEK_END 文件末尾,offset可正可负
返回值:成功返回定位后的文件位置偏移量;失败,返回-1L,并置errno
例:
//定位文件读写位置 off_t pos = lseek(fd,-5,SEEK_CUR);//相当于fseek//获得当前偏移量 pos = lseek(fd,0,SEEK_CUR);//相当于ftell//定位到文件开头 lseek(fd,0,SEEK_SET);//rewind//定位到文件结尾 lseek(fd,0,SEEK_END);//求文件长度 off_t len = lseek(fd,0,SEEK_END);注意:如果offset值大于文件实际大小,又进行了写入操作,会在文件中产生空洞
作业:写日志文件
/*{{{*/
1. 系统时间获取
#include <time.h> time_t time(time_t *t); //功能:获得utc起点到当前时间的秒数 // 传参方法 1.time_t tim = time(NULL); 2.time_t tim; time(&tim); //将秒数解释为年月日,时分秒 struct tm *localtime(const time_t *timep); struct tm { int tm_sec; /* seconds */ ** int tm_min; /* minutes */ ** int tm_hour; /* hours */ ** int tm_mday; /* day of the month */ ** int tm_mon; /* month */ ** int tm_year; /* year */ ** int tm_wday; /* day of the week */ int tm_yday; /* day in the year */ int tm_isdst; /* daylight saving time */ }; struct tm *tp = localtime(&tim); tp->tm_sec2.利用sleep()函数实现每秒写一次
unsigned int sleep(unsigned int seconds);/*}}}*/
#include <stdio.h>#include <errno.h>//errno#include <string.h> //strerror#include <time.h>#define N 100int get_line(FILE *fp){ char buf[N]={0}; int line = 0; while(fgets(buf,sizeof(buf),fp) != NULL) { if (buf[strlen(buf) - 1] == '\n') line++; } return line;}void printf_log(FILE *fp){ int line = 0; time_t tm; struct tm *ptm; line = get_line(fp); while(1) { time(&tm);//获取秒数 ptm = localtime(&tm); fprintf(fp,"%-4d, %04d-%02d-%02d %02d:%02d:%02d\n", line++,ptm->tm_year+1900,ptm->tm_mon+1, ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec); fflush(fp); fprintf(stdout,"%-4d, %04d-%02d-%02d %02d:%02d:%02d\n", line,ptm->tm_year+1900,ptm->tm_mon+1, ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec); sleep(1); } return ;}//./a.out logint main(int argc, const char *argv[]){ FILE *fp = NULL; int n = 0; if(argc != 2) { fprintf(stderr,"Usage: %s log\n",argv[0]); return -1; } if ((fp = fopen(argv[1],"a+")) == NULL) { fprintf(stderr,"fopen:%s\n",strerror(errno)); return -1; }#if 0 //统计行号 n = get_line(fp); printf("n = %d\n",n);#endif printf_log(fp); return 0;}文件目录操作:
打开,读,关闭
1.打开目录
#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *name);//功能:打开一个指定的目录,获得目录流指针//参数:// @name 指定打开的目录//返回值: //成功,返回可用的目录流; //失败,返回NULL,并置errno2.关闭目录
#include <sys/types.h>#include <dirent.h>int closedir(DIR *dirp);//功能:关闭一个打开的目录//参数: //@dirp 要关闭的目录流//返回值 : //成功 返回0; //失败 返回-1,并置errno3.读目录
#include <dirent.h>struct dirent *readdir(DIR *dirp);//功能:读一个目录(读目录下文件的属性,包括文件名,inode号,文件类型)//参数: //@dirp 要读的目录流指针//返回值: //成功,返回目录下一个文件的struct dirent结构首地址,返回NULL,读到结尾并且errno不变; //出错,返回NULL,并置errno struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ };练习:
读一个指定目录,计数其中普通文件个数,目录文件个数,不包括隐藏文件。
#include <stdio.h>// ./a.out fileint main(int argc, const char *argv[]){ int buf[100] = {0}; int n = 0; FILE *fp; if((fp = fopen(argv[1],"r")) == NULL) { perror("fopen"); return -1; } while((n = fread(buf,sizeof(int),sizeof(buf)/sizeof(int),fp))) printf("n = %d\n",n); return 0;}二、获得文件属性
#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>int stat(const char *path, struct stat *buf);//功能:获得文件属性//参数: //@path 指定文件路径 //@buf 保存属性信息内存区域首地址,传参需定义变量,传首地址//返回值:成功返回0;失败返回-1,并置errno struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ 关注 mode_t : unsigned int nlink_t st_nlink; /* number of hard links */ 关注 uid_t st_uid; /* user ID of owner */ 关注 uid_t : unsigned int gid_t st_gid; /* group ID of owner */ 关注 dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ 关注 blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ 关注 time_t st_ctime; /* time of last status change */ }; The following flags are defined for the st_mode field: //文件类型 S_IFMT 0170000bit mask for the file type bit fields S_IFSOCK 0140000socket S_IFLNK 0120000symbolic link S_IFREG 0100000regular file S_IFBLK 0060000block device S_IFDIR 0040000directory S_IFCHR 0020000character device S_IFIFO 0010000FIFO S_ISUID 0004000set UID bit S_ISGID 0002000set-group-ID bit (see below) S_ISVTX 0001000sticky bit (see below) //文件所有者权限 S_IRWXU 00700mask for file owner permissions S_IRUSR 00400owner has read permission S_IWUSR 00200owner has write permission S_IXUSR 00100owner has execute permission //同组用户权限 S_IRWXG 00070mask for group permissions S_IRGRP 00040group has read permission S_IWGRP 00020group has write permission S_IXGRP 00010group has execute permission //其它用户权限 S_IRWXO 00007mask for permissions for others (not in group) S_IROTH 00004others have read permission S_IWOTH 00002others have write permission S_IXOTH 00001others have execute permission获得文件类型方法
st_mode & S_IFMT 可能得到七种不同结果
分别对应七种文件类型
例:
switch(st_mode & S_IFMT){case S_IFSOCK: putchar('s'); break;case S_IFREG: putchar('-'); break;}//也可用S_ISREG(st_mode)判断//获得文件权限方法st_mode & S_IRUSRif(st_mode & S_IRUSR){ putchar('r');}else{ putchar('-');}获得文件所有者的方法
需要st_uid 和 /etc/passwd
利用
getpwuid()
可以实现转换
#include <sys/types.h> #include <pwd.h> struct passwd *getpwuid(uid_t uid); struct passwd { char *pw_name; /* username */关注 char *pw_passwd; /* user password */ uid_t pw_uid; /* user ID */ gid_t pw_gid; /* group ID */ char *pw_gecos; /* user information */ char *pw_dir; /* home directory */ char *pw_shell; /* shell program */ };//用法:getpwuid(st_uid)->pw_name获得文件所属组名的方法
需要st_gid和/etc/group
利用
getgrgid()
实现转换
#include <sys/types.h> #include <grp.h> struct group *getgrgid(gid_t gid); struct group { char *gr_name; /* group name */关注 char *gr_passwd; /* group password */ gid_t gr_gid; /* group ID */ char **gr_mem; /* group members */ };//用法:getgrgid(st_gid)->gr_name获得文件最后修改时间
st_mtime和localtime()
#include <time.h> struct tm *localtime(const time_t *timep); struct tm { int tm_sec; /* seconds */ int tm_min; /* minutes */ int tm_hour; /* hours */ int tm_mday; /* day of the month */ int tm_mon; /* month */ int tm_year; /* year */ int tm_wday; /* day of the week */ int tm_yday; /* day in the year */ int tm_isdst; /* daylight saving time */ };//用法:struct tm *tp = localtime(&st_mtime);练习:利用stat(2)和 readdir(3)函数实现ls -l命令功能
1.实现 ls -l file
类似
$ls -l src
-rwxr-xr-x 1 will will 7547 Apr 30 15:58 src
2.实现 ls -l dir
类似
$ls -l /home/will/IO/apr30/
-rwxrwxr-x 1 will will 7513 Apr 30 17:05 a.out
-rw-rw-r-- 1 will will 1287 Apr 30 14:11 copy_file.c
-rw-r--r-- 1 will will 1171 Apr 30 16:22 copy_file_io.c
-rw-rw-r-- 1 will will 1024 Apr 30 16:37 dest
drwxrwxr-x 2 will will 32768 Apr 30 09:37 dir
-rw-rw-r-- 1 will will 917 Apr 30 17:08 dir.c
-rw-rw-r-- 1 will will 1061 Apr 30 11:46 fread_fwrite.c
-rw-rw-r-- 1 will will 833 Apr 30 16:42 lseek.c
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <pwd.h>#include <grp.h>#include <time.h>#include <sys/types.h>#include <dirent.h>#include <string.h>int dispaly_file_stat(const char *path){struct stat f_info;struct tm *ptm;stat(path,&f_info);//file typeswitch(f_info.st_mode & S_IFMT){case S_IFSOCK: putchar('s'); break;case S_IFLNK : putchar('l'); break;case S_IFREG : putchar('-'); break;case S_IFBLK : putchar('b'); break;case S_IFDIR : putchar('d'); break;case S_IFCHR : putchar('c'); break;case S_IFIFO : putchar('p'); break;}//pesimision//ownerf_info.st_mode & S_IRUSR ? putchar('r'):putchar('-');f_info.st_mode & S_IWUSR ? putchar('w'):putchar('-');f_info.st_mode & S_IXUSR ? putchar('x'):putchar('-');//groupf_info.st_mode & S_IRGRP ? putchar('r'):putchar('-');f_info.st_mode & S_IWGRP ? putchar('w'):putchar('-');f_info.st_mode & S_IXGRP ? putchar('x'):putchar('-');//otherf_info.st_mode & S_IROTH ? putchar('r'):putchar('-');f_info.st_mode & S_IWOTH ? putchar('w'):putchar('-');f_info.st_mode & S_IXOTH ? putchar('x'):putchar('-');//nlink printf("%3d ",f_info.st_nlink); //ower nameprintf("%s ",getpwuid(f_info.st_uid)->pw_name);//group nameprintf("%s ",getgrgid(f_info.st_gid)->gr_name);//file sizeprintf("%8ld ",f_info.st_size);//timeptm = localtime(&f_info.st_mtime);printf("%4d-%02d-%02d %02d:%02d:%02d ",ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec);//file nameprintf("\t%s ",path);printf("\n");return 0;}int dispaly_dir_file(const char *path){ DIR *dir = NULL;struct dirent *pd;char buf[100] = {0};if((dir = opendir(path)) == NULL){perror("opendir");return -1;}while((pd = readdir(dir)) != NULL){//printf("%s\n",pd->d_name);//对文件路径处理,可实现不同目录下的遍历显示if(path[strlen(path) - 1] == '/'){sprintf(buf,"%s%s",path,pd->d_name);}else{sprintf(buf,"%s/%s",path,pd->d_name);}dispaly_file_stat(buf);}closedir(dir);return 0;}// ./a.out fileint main(int argc, const char *argv[]){ if (argc !=2 ){ fprintf(stderr,"Usage:%s file\n",argv[0]); return -1; } //dispaly_file_stat(argv[1]); dispaly_dir_file(argv[1]); return 0;}
0 0
- Linux文件I/O(6.1)
- Linux文件I/O
- linux 文件I/O
- Linux文件I/O
- Linux----文件I/O
- LINUX 文件I/O
- linux文件I/O
- Linux -- 文件I/O
- Linux 文件I/O
- Linux 文件I/O
- Linux-文件I/O
- Linux文件I/O操作
- linux 文件I/O 编程
- linux 文件I/O API
- Linux 文件I/O编程
- linux文件I/O编程
- linux 文件I/O 入门
- 1.linux文件I/O
- 继承、抽象类和接口的特点与关系
- 有关HashSet遇到的问题
- 第七章第一题
- 母函数知识点,感觉讲的还可以
- KillTimer
- Linux文件I/O(6.1)
- 自定义带字数统计和限制的EditText
- 百度地图SDK调试SDKInitializer.initialize(getApplicationContext())错误
- 多线程编程(一)之 block 与 dispatch quene
- 为什么说找不到标识符!???
- Andrew NG机器学习课程笔记(九)
- Android 快速开发框架:推荐10个框架:afinal、ThinkAndroid、andBase、KJFrameForAndroid、SmartAndroid、dhroid..
- MYSQL数据库管理之权限管理
- Groovy入门教程