文件基础
概念:
一组相关数据的有序集合
文件类型
不同操作系统支持的文件类型是不相同的,这里列出的是linux
常规文件 r
目录文件 d
字符设备文件 c
块设备文件 b
管道文件 p
套接字文件 s
符号链接文件 l
标准I/O
由ANSI C标准定义
主流操作系统上都实现了C库
特点: 标准I/O通过缓冲机制减少系统调用,实现更高的效率
FILE
标准IO用一个结构体类型来存放打开文件的相关信息
标准IO的所有操作都是围绕FILE来进行的
流(stream)
FILE又被称为流(stream)又被分为文本流、二进制流两种
windows:
二进制流:换行符 -- '\n'
文本流:换行符 -- '\r''\n'
linux
换行符:'\n'
流的缓冲类型
全缓冲:
当流的缓冲区无数据或空间时才执行实际I/O操作
行缓冲:
当在输入和输出中遇到换行符时,才执行I/O操作
当流和一个终端关联时,典型的行缓冲
无缓冲:
数据直接写入文件,流不进行缓冲
标准I/O预定的3个流,程序运行时自动打开
标准输入流
0
STDIN_FILENO
stdin
标准输出流
1
STDOUT_FILENO
stdout
标准错误流
2
STDERR_FILENO
stderr
流打开
FILE *fopen(const char * path,const char *mode)
成功时返回流指针;错误返回NULL
- 当用fopen新建文件后,该文件的权限为0666(rw-rw-rw-)
- 在linux系统中 umask设定会影响文件的权限访问 可以通过umask函数进行对应的修改
mode参数:
"r"或"rb"
以只读的方式打开文件,文件必须存在
"r+"或"r+b"
以读写的方式打开文件,文件必须存在
"w"或"wb"
以只写的方式打开文件,若文件存在则文件长度清零。若文件不存在则创建
"w+"或"w+b"
以只写方式打开文件,其他同"w"
"a"或"ab"
以只写的方式打开文件,若文件不存在则创建;向文件写入的数据将被追加到文件末尾
"a+"或"a+b"
以读写的方式打开文件。其他同"a"
*当给"b"参数时候,表示以二进制方式打开文件,但Linux下忽略该参数
错误流处理
void perror(const char *)
输入提示关键字 捕获当前错误并加输入的关键字返回
打印错误信息 例如
intmain() {
FILE*fp;if ((fp = fopen("test","r+"))==NULL){
perror("fopen");return -1;
}
}//out//fopen: No such file or directory
#include #include //需要引入
#include //需要引入 标准错误输入
intmain() {
FILE*fp;if ((fp = fopen("test","r+"))==NULL){
printf("fopen:%s",strerror(errno));return -1;
}
}
判断是否出错或结束
#include
int ferror(FILE *stream);int feof(FILE *stream);//ferror()返回1表示流出错;否则返回0//feof()返回1表示已经到末尾,否则返回0
读写流
流支持不同的读写方式
读写一个字符:
//fgetc()/fputc() 一次读/写一个字符
输入
#include
int fgetc(FILE *stream);int getc(FILE *stream);int getchar(void);//成功时返回读取的字符//若到文件的末尾或出错返回EOF
Demo:
#include
intmain() {intch;
ch= fgetc(stdin); //从标准输入获取
printf("%c", ch);
}
#include
intmain() {
FILE*fp;int ch = 0;int i = 0;int count = 0;if ((fp = fopen("./a.out", "r")) ==NULL) {
perror("fopen");return -1;
}while ((ch = fgetc(fp)) !=EOF) {
count++;
}
printf("文本长度 :%d", count);
}
输出
#include
int fputc(int c,FILE *stream);int putc(int c,FILE *stream);int putchar(intc);//成功时返回写入的字符//出错时返回EOF
Demo:
#include
intmain() {
putc('a',stdout);
putchar('\n');
}//out//a//
#include
intmain() {
FILE*fp;int ch = 0;if ((fp = fopen("./a.out", "w")) ==NULL) {
perror("fopen");return -1;
}for (ch = 'a'; ch <= 'z', ch++;) {
fputc(ch,fp);//输出到文本
}
}
文件copy
#include
int main(int argc, char *argv[]) {
FILE*src, *desc;inti;if (argc < 3) {
puts("Few parameters:project : ");return -1;
}//打开目标文件
if ((src = fopen(argv[1], "r")) ==NULL) {
perror("src:");return -1;
}if ((desc = fopen(argv[2], "w")) ==NULL) {
perror("desc:");
fclose(src);//失败释放打开的句柄
return -1;
}while ((i = fgetc(src)) !=EOF) {
fputc(i, desc);
}
fclose(src);
fclose(desc);
}
读写一行:
//fgets()/fputs() 一次读/写一行
输入
#include
char *gets(char *s);char *fgets(char *s,int size,FILE *stream);//成功时返回s,到文件末尾或出错时返回NULL//gets不推荐使用,容易造成缓冲区溢出;//***遇到'\n'或已输入size-1个字符返回时,总是包含'\0'
输出
#include
int puts(const char *s);int fputs(const char *s,FILE *stream);//成功时返回输出的字符个数//出错返回EOF//puts将缓冲区s中的字符串输出到stdout,并追加'\n'
demo:
#include
int main(int argc, char *argv[]) {
FILE*fp;char buf[] = "hello world";if ((fp = fopen(argv[1], "a")) ==NULL) {
perror("fopen");return -1;
}
fputs(buf, fp);
}
读写若干个对象:
//fread()/fwrite() 每次读/写若干个对象,而每个对象具有相同的长度
#include size_t fread(void *ptr,size_t size,size_t n,FILE *fp); //容器指针,存储元素的长度,读取的长度,文件句柄
size_t fwrite(const void *prt,size_t size,size_t n,FILE *fp);//成功返回读写的对象个数//出错返回EOF
demo
#include
int main(int argc, char *argv[]) {
FILE*fp;int buf[10] ={};if ((fp = fopen(argv[1], "a")) ==NULL) {
perror("fopen");return -1;
}if (fread(buf, sizeof(int), 10, fp) < 0) {
perror("fread");return -1;
}
}
copy文件
#include
#define N 1024
int main(int argc, char *argv[]) {
FILE*src, *desc;int i[N] ={};int n = 0;if (argc < 3) {
puts("Few parameters:project : ");return -1;
}//打开目标文件
if ((src = fopen(argv[1], "r")) ==NULL) {
perror("src:");return -1;
}if ((desc = fopen(argv[2], "w")) ==NULL) {
perror("desc:");
fclose(src);//失败释放打开的句柄
return -1;
}if ((n = fread(i, sizeof(int), N, src)) > 0) {
fwrite(i, n,sizeof(int), desc);
}
fclose(src);
fclose(desc);
}
刷新流
fflush()
#include
int fflush(FILE *fp);//成功时返回0//出错返回EOF
刷新会将缓冲区的内容落盘
定位流
ftell/fseek/rewind
#include
long ftell(FILE *stream);long fseek(FILE *stram,long offset,int whence); //offset表示偏移量 可正可负 whence表示基准点
void rewind(FILE *stram);//ftell()成功时返回流的当前读写位置,错误时返回EOF//fseek()定位一个流,成功时返回0,出错时返回EOF//whence参数:SEEK_SET-文件开头/SEEK_CUR-当前位置/SEEK_END-文件结尾//rewind将流定位到起始位置//读写流时,当前读写位置自动后移
Demo:
在文件末尾增加字符't'
#include
int main(int argc, char *argv[]) {
FILE*fp;//打开目标文件
if ((fp = fopen(argv[1], "r")) ==NULL) {
perror("src:");return -1;
}//移动到文章末尾
fseek(fp, 0, SEEK_END);//增加字符t
fputc('t', fp);
fclose(fp);
}
获取文件长度
#include
int main(int argc, char *argv[]) {
FILE*fp;inti;//打开目标文件
if ((fp = fopen(argv[1], "r")) ==NULL) {
perror("src:");return -1;
}//移动到文章末尾
fseek(fp, 0, SEEK_END);//获取文件长度
i =ftell(fp);
printf("长度为%d",i);
fclose(fp);
}
格式化输出
#include
int printf(const char *fmt,...);int fprintf(FILE *stream,const char *fmt,...)int sprintf(char *s,const char *fmt,...)//成功时返回输出的字符个数//出错时返回EOF
#include
int main(int argc, char *argv[]) {
FILE*fp;intyear, month, day;char buf[64];//打开目标文件
if ((fp = fopen(argv[1], "r")) ==NULL) {
perror("src:");return -1;
}
year= 2020;
month= 05;
day= 05;//输入到fp的流中
fprintf(fp, "%d-%d-%d", year, month, day);//输入到缓冲区中
sprintf(buf, "%d-%d-%d", year, month, day);
}
关闭流
int fclose(FILE *stream);
调用成功返回0,失败返回EOF,并设置errno
流成功关闭后会自动刷新缓冲中的数据并释放缓冲区
当一个程序正常终止时,所有打开的流都会被关闭
流一旦关闭将不能对其执行任何操作
在linux中打开流的最大个数(修改ulimit可更改)
1021 + stdin + stdout + stderr = 1024
文件I/O
POSIX(可移植操作系统接口)定义的一组函数
不提供缓冲机制,每次读写操作都引起系统调用
核心概念是文件描述符
可以访问各种类型文件
在Linux下,标准IO基于文件IO实现
文件描述符
每一个打开的文件都对应一个文件描述符
文件描述符是一个非负整数。Linux为程序中每打开的问你件分配一个文件描述符
文件描述符从0开始分配,一次递增
文件IO操作通过文件描述符来完成
文件描述符的0,1,2的含义
分别是标准输入,标准输出,标准错误 一一对应
打开文件、创建文件
#include
int open(const char *path,intoflag,mode_t mode);//path文件路径//oflag打开方式,可以是多个参数//当open成功时返回文件描述符//出错返回EOF//创建文件时第三个参数指定文件的权限//设备文件只能打开不能创建
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件. 上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(|)运算符组合.
O_CREAT 若欲打开的文件不存在则自动建立该文件.
O_EXCL 如果O_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否则将导致打开文件错误. 此外, 若O_CREAT 与O_EXCL 同时设置, 并且欲打开的文件为符号连接, 则会打开文件失败.
O_NOCTTY 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
O_TRUNC 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 而原来存于该文件的资料也会消失.
O_APPEND 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面.
O_NONBLOCK 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中.
O_NDELAY 同O_NONBLOCK.
O_SYNC 以同步的方式打开文件.
O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接, 则会令打开文件失败.
O_DIRECTORY 如果参数pathname 所指的文件并非为一目录, 则会令打开文件失败。注:此为Linux2. 2 以后特有的旗标, 以避免一些系统安全问题.
参数mode 则有下列数种组合, 只有在建立新文件时才会生效, 此外真正建文件时的权限会受到umask 值所影响, 因此该文件权限应该为 (mode-umaks).
S_IRWXU00700 权限, 代表该文件所有者具有可读、可写及可执行的权限.
S_IRUSR 或S_IREAD, 00400 权限, 代表该文件所有者具有可读取的权限.
S_IWUSR 或S_IWRITE, 00200 权限, 代表该文件所有者具有可写入的权限.
S_IXUSR 或S_IEXEC, 00100 权限, 代表该文件所有者具有可执行的权限.
S_IRWXG 00070 权限, 代表该文件用户组具有可读、可写及可执行的权限.
S_IRGRP 00040 权限, 代表该文件用户组具有可读的权限.
S_IWGRP 00020 权限, 代表该文件用户组具有可写入的权限.
S_IXGRP 00010 权限, 代表该文件用户组具有可执行的权限.
S_IRWXO 00007 权限, 代表其他用户具有可读、可写及可执行的权限.
S_IROTH 00004 权限, 代表其他用户具有可读的权限
S_IWOTH 00002 权限, 代表其他用户具有可写入的权限.
S_IXOTH 00001 权限, 代表其他用户具有可执行的权限.
Demo:
#include #include
//以只写的方式打开文件,如果不存在则创建,如果存在则清空
int main(int argc, char *argv[]) {intfd;if ((fd = open("1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
perror("open");
}
}
#include #include#include //需要引入
#include //需要引入 标准错误输入//以读写的方式打开文件,如果不存在则创建,如果存在则报错
int main(int argc, char *argv[]) {intfd;if ((fd = open("1.txt", O_RDWR | O_CREAT, 0666)) < 0) {if (errno ==EEXIST) {
perror("exist error");
}else{
perror("other error");
}
}
}
读取文件
#include ssize_t read(int fd,void *buf,size_t count); //buf容器 count 一般定为缓冲区的大小 保证缓冲区不会溢出//成功返回实际读取的字节数//失败返回EOF//读到文件尾时返回0
demo:统计文件大小
#include #include#include
int main(int argc, char *argv[]) {intfd, n, total;char buf[64];if ((fd = open(argv[1], O_RDONLY)) < 0) {
perror("open");return -1;
}//读取文件的内容//获取文件大小
while ((n = read(fd, buf, 64)) > 0) {
total+=n;
}
}
写入文件
#include ssize_t write(int fd,void *buf,size_t count);//成功时返回实际写入的字节数//出错返回EOF//count不应超过buf大小
demo:键盘输入
#include #include#include#include
int main(int argc, char *argv[]) {intfd;char buf[64];if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
perror("open");return -1;
}//读取文件的内容//获取文件大小
while (fgets(buf, 20, stdin) > 0) {if (strcmp(buf, "quit\n") == 0) {break;
}
write(fd, buf, strlen(buf));
}
}
demo:文件的复制
#include #include#include
#define N 64
int main(int argc, char *argv[]) {intsrc, desc;intn;charbuf[N];if (argc < 3) {
perror("Parameter less than 3");return -1;
}//打开源文件 只读
if ((src = open(argv[1], O_RDONLY)) < 0) {
perror("open src");return -1;
}//打开目标文件
if ((desc = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
perror("open desc");
close(src);return -1;
}//获取文件大小
while ((n = read(src, buf, N)) > 0) {
write(desc, buf, n);
}
close(src);
close(desc);
}
定位
#include off_t lseek(int fd,off_t offset,int whence); //与fseek类似 whence基准点一样//成功返回当前文件的读写位置//出错返回EOF
文件关闭
#include
int close(intfd);//成功时返回0//出错时返回EOF//程序结束时自动关闭所有打开的文件//文件关闭后,就不能对文件描述符进行操作
访问(打开)目录
#include DIR*opendir(const char*name); //name目录路径//DIR是用来描述一个打开的目录文件的结构体类型//成功时返回目录流指针//错误时返回NULL
查看目录内容
#include
struct dirent *readdir(DIR *dirp);//struct dirent是用来描述目录流中一个目录项的结构体类型//包含成员 char d_name[256] —— 文件名 其他参考帮助文档//成功时返回目录流dirp中下一个目录项//出错或到末尾是返回NULL
demo:查看指定目录下的文件名
#include #include
int main(int argc, char *argv[]) {
DIR*dirp;struct dirent *dp;if (argc < 2) {
perror("Parameter is less than 2");return -1;
}//打开目录
if ((dirp = opendir(argv[1])) ==NULL) {
perror("opendir");return -1;
}while ((dp = readdir(dirp)) !=NULL) {
printf("%s\n", dp->d_name);
}
closedir(dirp);
}
关闭目录流
#include
int closedir(DIR *dirp);//成功返回0//失败返回-1
修改文件的访问权限 chmod/fchmod
#include
int chomd(const char *path,mode_t mode);int fchmod(intfd,mode_t mode);//mode 例如 0666 权限码//成功时返回0//出错返回EOF//root用户和所有者才可以修改文件的访问权限//demo:
chomd("text.txt",0666);
获取文件的属性
#include
int stat(const char *path,struct stat *buf); //path为路径,buf为获取存放的结构体
int lstat(const char *path,struct stat *buf);int fstat(int fd,struct stat*buf);//stat与lstat区别: 如果path是符号链接stat获取到的是目标文件的属性,而lstat获取的是链接文件的属性//成功时返回0//出错返回EOF
//struct stat结构体属性//mode_t st_mode 文件类型和访问权限//uid_t st_uid 所有者id//uid_t st_gid 用户组id//off_t st_size 文件大小//time_t st_mtime 最后修改时间//....
mode_t st_mode 判断文件类型
//通过系统提供的宏来判断文件类型
st_mode & 0170000S_ISREG(st_mode)0100000S_ISDIR(st_mode)0040000S_ISCHR(st_mode)0020000S_ISBLK(st_mode)0060000S_ISFIFO(st_mode)0010000S_ISLNG(st_mode)0120000S_ISSOCK(st_mode)0140000
mode_t st_mode 获取权限
//通过系统提供的宏来获取we年访问权限//所有者
S_IRUSR——00400——8可读
S_IWUSR——00200——7可写
S_IXUSR——00100——6
//同组用户
S_IRGRP——00040——5S_IWGRP——00020——4S_IXGRP——00010——3
//其他组用户
S_IROTH——00004——2S_IWOTH——00002——1S_IXOTH——00001——0
//通过系统提供的宏来获取文件的访问权限//所有者
S_IRUSR——00400——8可读
S_IWUSR——00200——7可写
S_IXUSR——00100——6
//同组用户
S_IRGRP——00040——5S_IWGRP——00020——4S_IXGRP——00010——3
//其他组用户
S_IROTH——00004——2S_IWOTH——00002——1S_IXOTH——00001——0
来源:https://www.cnblogs.com/binHome/p/12840514.html