文章是在牛客学习高薪求职课程,高并发服务器时所写
因为篇幅太长,将分成两篇博客
目录
一、标准c库和Linux系统I/O函数
1.标准c库是跨平台的函数,能调用Linux的IO函数,相当于优先级更高
2.标准c库在读写时都有缓冲区,当下列几种情况才会将 数据从内存刷新到磁盘(1)刷新缓冲区:fflush
( 2).缓冲区已满
(3).正常关闭文件 a.fclose b.return(main函数) c.exit(main函数
但是Linux IO函数没有缓冲区,相对来说效率更慢
二、虚拟地址空间
三、文件描述符
1.进程控制块(PCB)中的文件描述符表前三行放置 标准输入 标准输出 标准错误 固定不可改变 0 -> STDIN_FILENO 1 -> STDOUT_FILENO 2 -> STDERR_FILENO (默认大小是1024),指向当前终端
2.同一个文件被同时打开多次,文件指针定位的文件描述符都不一样
3. 每打开一个新文件, 则占用一个文件描述 符,而且是空闲的最 小的一个文件描述符
4.Linux文件操作是通过文件描述符所对应那个文件去操作
四、系统I/O函数以及讲解
1.int open(const char *pathname, int flags);
2.int open(const char *pathname, int flags, mode_t mode);
3.int close(int fd);
4.ssize_t read(int fd, void *buf, size_t count);
5.ssize_t write(int fd, const void *buf, size_t count);
6.off_t lseek(int fd, off_t offset, int whence);
7.int stat(const char *pathname, struct stat *statbuf);
8.int lstat(const char *pathname, struct stat *statbuf);
1.open函数打开一个文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>//打开一个已经存在的文件
int open(const char *pathname, int flags);
pathname:文件路径
flags:对文件的权限设置还有其他设置
O_RDONLY, O_WRONLY, or O_RDWR 只读,只写,可读可写,通常是互斥的
返回值: open(), openat(), and creat() return the new file descriptor, or -1 if an
error occurred(in which case, errno is set appropriately)
errno:属于Linux函数库里面的一个全局变量,记录最近的错误号 每个错误都有一个错误号
/*
#include <stdio.h>
void perror(const char *s); 作用:打印errno对应的错误描述
s:用户描述,比如hello,最终输出的内容是hello:xxx(最终的错误信息)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd = open("a.txt",O_RDONLY);
if(fd == -1){
perror("open");
}
close(fd);
return 0;
}
2.open函数打开并创造文件
头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags, mode_t mode);
pathname:文件路径
flags:对文件的权限设置还有其他设置
必选项:O_RDONLY, O_WRONLY, or O_RDWR 只读,只写,可读可写,通常是互斥的
可选项:O_CREAT:文件不存在,创建文件
flags:int类型,每一位都是一个标志位
mode:八进制数,表示创造出的文件的操作权限
最终的权限:mode &~umask umask的作用是抹去某一些权限
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd = open("create.txt", O_RDWR | O_CREAT, 0777);
if(fd == -1){
perror("open");
}
close(fd);
return 0;
}
3.read、write函数:
头文件:#include <unistd.h>
函数原型:ssize_t read(int fd, void *buf, size_t count);
参数:
fd:文件描述符,open得到,通过文件描述符操作某个文件
buf:读取数据存放的地方,一般是数组的地址(传出参数)
count:指定的数组大小
返回值:
成功:>0返回实际读取到的字节数
=0 文件已经读取完成
失败:-1,并且设置error
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符,open得到,通过文件描述符操作某个文件
buf:要往磁盘写入的数据
count:写入数据实际的大小
返回值:
成功:返回写入的字节数
失败:返回-1,并设置error
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int srcfd = open("english.txt",O_RDONLY);
if(srcfd==-1){
perror("open");
return -1;
}
int destfd = open("cpy.txt",O_WRONLY | O_CREAT,0664);
char buf[1024] = {0};
int len = 0;
while((len = read(srcfd,buf,sizeof(buf)))>0 ){
write(destfd,buf,len);
}
close(srcfd);
close(destfd);
return 0;
}
4.lseek函数
标准c库
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
Linux系统函数
#include <sys/types.h>
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
参数:
fd:文件描述符
offset:偏移量
whence:
SEEK_SET:设置文件指针偏移量
SEEK_CUR:设置偏移量:当前位置+第二个参数offset的值
SEEK_END:设置偏移量:文件大小 + 第二个参数offset的值
返回值:返回文件指针位置
作用:
1.移动文件指针到头文件
lseek(fd,0,SEEK_SET);2.获取当前文件指针位置:
lssek(fd,0,SEEK_CUR)3.获取文件长度
lseek(fd,0,SEEK_END)4.拓展文件的长度:如当前文件10b——》110b,增加100个字节
lseek(fd,100,SEEK_END)
注意:需要写入一次数据
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<stdio.h>
int main()
{
int fd = open("hello.txt",O_RDWR);
if(fd ==-1){
perror("open");
}
//拓展文件长度
int ret = lseek(fd,100,SEEK_END);
//写入一个空字符串
write(fd," ",1);
if(ret==-1)
{
perror("lseek");
return -1;
}
close(fd);
return 0;
}
5.state,lstate函数
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
作用:获取文件相关的信息
参数:
pathname:路径
statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
返回值:
成功:返回0
失败:返回-1 设置errno
int lstat(const char *pathname, struct stat *statbuf);
作用:获取文件软连接的信息 软连接:通过命令:ln -s a.txt b.txt生成的b.txt 就是指向a的软连接
参数:
pathname:路径
statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
返回值:
成功:返回0
失败:返回-1 设置errno
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
struct stat statbuf;
int ret = stat("a.txt", &statbuf);
if(ret == -1){
perror("stat");
return -1;
}
printf("size:%ld\n",statbuf.st_size);
return 0;
}
模拟实现ls指令
//模拟实现ls -l指令
//-rw-rw-r-- 1 china china 11 7月 1 21:54 a.txt
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include<stdio.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<string.h>
int main(int argc,char * argv[])
{
//判断输入参数是否正确
if(argc < 2){
printf("%s filename",argv[0]);
return -1;
}
//通过stat函数获取用户传入的文件的信息
struct stat st;
int ret = stat(argv[1],&st);
if(ret == -1){
perror("stat");
return -1;
}
//获取文件类型和文件权限
char perms[11] ={0}; //用于保存文件类型和文件权限
switch(st.st_mode & __S_IFMT){
case __S_IFLNK:
perms[0] = '1';
break;
case __S_IFDIR:
perms[0] = 'd';
break;
case __S_IFREG:
perms[0] = '-';
break;
case __S_IFBLK:
perms[0] = 'b';
break;
case __S_IFCHR:
perms[0] = 'c';
break;
case __S_IFSOCK:
perms[0] = 's';
break;
case __S_IFIFO:
perms[0] = 'p';
break;
default:
perms[0] = '?';
}
//判断文件访问权限
//文件所有者
perms[1] =(st.st_mode & S_IRUSR) ? 'r':'-';
perms[2] =(st.st_mode & S_IWUSR) ? 'w':'-';
perms[3] =(st.st_mode & S_IXUSR) ? 'x':'-';
//文件所在组
perms[4] =(st.st_mode & S_IRGRP) ? 'r':'-';
perms[5] =(st.st_mode & S_IWGRP) ? 'w':'-';
perms[6] =(st.st_mode & S_IXGRP) ? 'x':'-';
//其他人
perms[7] =(st.st_mode & S_IROTH) ? 'r':'-';
perms[8] =(st.st_mode & S_IWOTH) ? 'w':'-';
perms[9] =(st.st_mode & S_IXOTH) ? 'x':'-';
//硬链接数
int linkNum = st.st_nlink;
//文件所有者
char * fileuser = getpwuid(st.st_uid)->pw_name;
//文件所在组
char * fileGrp = getgrgid(st.st_gid)->gr_name;
//文件大小
long int fileSize = st.st_size;
//获取修改时间
char * time = ctime(&st.st_mtime);
char mtime[512] ={0};
strncpy(mtime,time,strlen(time)-1);//为了去掉时间转换后的换行
char buf[1024];
sprintf(buf,"%s %d %s %s %ld %s %s",perms,linkNum,fileuser,fileGrp,fileSize,mtime,argv[1]);
printf("%s\n",buf);
return 0;
}