1.标准io和文件io
1.标准io和文件io的区别:
标准io的函数是库函数,不涉及内核层和用户层的上下文切换,效率更高, 库函数不依赖内核的服务,只需要平台提供相应的库,就可以运行库函数,库函数是对内核函数的二次封装,它提供了一个缓存区,每次写数据,先存放到缓存区,当缓存区刷新条件满足时,多个数据同时通过系统调用,从缓存区传到内核空间,避免了频繁访问内核,比系统调用函数效率更高。
文件io的函数是系统调用函数,系统调用函数是内核提供给用户用来调用内核函数服务的,每次都需要通过软中断等指令去调用内核空间中相应的内核函数,涉及频繁地内核和用户之间的上下文切换,调用系统调用函数,会导致出现进程的上下文切换,进程会进入休眠状态,休眠被唤醒会进入就绪队列,排队等待获取时间片,因此效率更低。
可以看做:标准io = 文件io+缓存区
2.标准io缓存区刷新
行缓存刷新:对应stdout,流向终端的标准错误流使用行缓存:1024字节
遇到回车刷新,缓存区满刷新,程序结束刷新,io关闭刷新,io切换刷新,
调用fflush(FILE*)手动刷新
全缓存刷新:对应fopen打开的文件使用全缓存:4096字节
除了遇到回车不刷新外,其他和行缓存刷新一致
无缓存刷新:流向终端的标准错误流使用无缓存:0字节
errno被赋值int类型的数据,例如赋值2对应错误信息为:No such file or director
2.标准io的函数
1.fopen
FILE *fopen(const char *pathname, const char *mode);
功能:打开文件,通过mode方式打开,通过返回值对文件进行读写操作。
参数:
参数1:文件路径。
参数2:打开方式w,w+,r,r+,a,a+,
返回值:成功返回打开文件的指针,失败返回空指针NULL
2.fclose
fclose(FILE *fp)
3.fprintf
int fprintf(FILE *stream, const char *format, ...);
功能:将format写入到stream指向的文件中
int sprintf(char *str, const char *format, ...)
功能:将任意数据类型转为字符串类型
4.fscanf
int fscanf(FILE *stream, const char *format, ...);
功能:将stream指向的文件中的内容读到format指向的变量中
int sscanf(const char *str, const char *format, ...)
功能:将字符串类型转为任意数据类型
5.三个特殊的FILE*文件指针
stdin,stdout,stderr
分别对应scanf,printf,errno
6.feof
int feof(FILE *stream)
功能:判断文件是否读到末尾,读到末尾则返回1,没有读到结尾返回0
7.fgetc,fputc,fgets,fputs
8.fwrite,fread
9.fseek
3.文件io的函数
1.open
int open(const char *pathname, int flags, mode_t mode);
2.read,write
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
3.文件重定向
int dup2(int oldfd, int newfd);
功能描述:让newfd描述符,重定向到oldfd里面去
举例:dup2(fd,2) 此时调用函数:perror("err"),错误信息就会输出到fd所代表的文件中去
int dup(int oldfd);
功能描述:使用最小未使用的描述符位置处,记录一下oldfd所代表的文件指针,并返回记录处的下标位置
//练习:
//使用dup和dup2实现以下功能:
//有这样的2条代码:
//printf("hello\n");
//printf("world\n");
//要求hello输出到文件中,world输出到终端上
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
int fd;
fd = open("./myfile", O_RDWR | O_CREAT | O_TRUNC, 0666);
if(fd < 0)
{
perror("open error");
return -1;
}
int sav = dup(1);
printf("hello\n");
dup2(fd, 1);
printf("world\n");
return 0;
}
4.判断文件权限
int access(const char *pathname, int mode);
功能描述:判断当前程序是否能够以mode形式访问 pathname文件
参数mode:有以下4个选项 F_OK:判断文件是否存在 R_OK:判断文件是否可读 W_OK:判断文件是否可写 X_OK:判断文件是否可执行
返回值:如果能够访问,返回0, 不能访问返回-1
5.获取文件属性
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
上面这三个函数功能相同,都是获取文件属性到struct stat类型的结构体指针中
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
struct stat buf;
stat("./myfile",&buf);
if(buf.st_mode | S_IRGRP == buf.st_mode)
{
printf("文件可读\n");
}
}
6.设置掩码umask
什么叫做掩码:其实我们文件创建的时候,真正的文件权限 = 指定的权限 &~ 掩码值
例如:现在 掩码的值是 0111
创建文件的时候,权限是 0777,最终的文件权限值是 0666
创建文件的时候,权限是 0444,最终的文件权限值是 0444
创建文件的时候,权限是 0111,最终的文件权限值是 0000