个人主页:点我进入主页
专栏分类:C语言初阶 C语言进阶 数据结构初阶 Linux C++初阶 算法 C++进阶
欢迎大家点赞,评论,收藏。
一起努力,一起奔赴大厂
目录
一.重定向
1.1stat接口
1.1.1利用stat查看文件大小
1.1.2利用stat读取文件
1.2文件描述符分配规则
1.2.1分别关闭文件描述符
1.2.2只关闭1
1.3dup2
1.4标准错误重定向
二.缓冲区
2.1刷新策略
2.2封装一下库
一.重定向
1.1stat接口
首先我们先写入文件
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd=open("test.txt",O_CREAT|O_WRONLY|O_TRUNC,0666);
if(fd<0)
{
perror("fopen\n");
return 1;
}
const char * message="hello Linux\n";
write(fd,message,strlen(message));
write(fd,message,strlen(message));
write(fd,message,strlen(message));
close(fd);
return 0;
}
文件test.txt写入
我们可以使用
man 2 stat
stat是一个结构体,类型为struct stat,我们可以查到stat的结构体里面有
1.1.1利用stat查看文件大小
我们现在主要使用它的st_size属性, 我们看代码:
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
const char * filename="test.txt";
int main()
{
struct stat st;
stat(filename,&st);
printf("file size : %d\n",st.st_size);
int fd=open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
if(fd<0)
{
perror("fopen\n");
return 1;
}
printf("fd : %d \n",fd);
// const char * message="hello Linux\n";
// write(fd,message,strlen(message));
// write(fd,message,strlen(message));
// write(fd,message,strlen(message));
close(fd);
return 0;
}
运行结果为:
1.1.2利用stat读取文件
通过read进行文件读取,读取的个数就是文件的大小,代码如下:
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include<stdlib.h>
const char *filename="test.txt";
int main()
{
struct stat st;
stat(filename,&st);
printf("file size : %d\n",st.st_size);
int fd=open(filename,O_RDONLY);
if(fd<0)
{
perror("fopen\n");
return 1;
}
char* message=(char*)malloc(st.st_size+1);
int n =read(fd,message,st.st_size);
if(n>0)
{
message[st.st_size]='\0';
printf("%s\n",message);
}
else
{
perror("read");
return 2;
}
close(fd);
return 0;
}
1.2文件描述符分配规则
1.2.1分别关闭文件描述符
文件描述符的分配规则就是按照从小到大进行分配,查询到一个最小的文件描述符,其中0,1,2分别是标准输入,标注输出,标注错误这三个,在这里重点不在这里,我尝试关闭0,1,2输出一些内容,可以看到什么,代码如下:
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include<stdlib.h>
const char *filename="test.txt";
int main()
{
//close(0);
//close(1);
//close(2);
printf("hello linux\n");
return 0;
}
分别关闭0,1,2结果为:
1.2.2只关闭1
只关闭文件描述符1,再打开一个文件,那这个文件的文件描述符是1,文件描述符1是标准输出啊,先看代码:
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include<stdlib.h>
const char *filename="test.txt";
int main()
{
close(1);
int fd=open("test.txt",O_CREAT|O_WRONLY|O_TRUNC,0666);
if(fd<0)
{
perror("open\n");
return 1;
}
printf("printf fd: %d\n",fd);
fprintf(stdout,"fprintf fd: %d\n",fd);
fflush(stdout);
close(fd);
return 0;
}
再显示器中没有任何输出,它的输出在text.txt文件中
如果我们删除fflush(stdout)这句test.txt就不会有任何内容,下面图片可以大致表示此过程:
关闭1,再打开一个文件,这个文件的文件描述符为1,由于上层不知道底层的变化,所以stdout的文件描述符还是1,文件描述符1对应着stdout,在stdout写入,会存储在它的语言级缓冲区,当程序结束会刷新这个缓冲区,但是我们文件关闭了所以当没有fflush就不会有内容,有fflush会将语言级缓存区内容刷新到内核级文件缓冲区中,然后再刷入磁盘。这个操作就是一种重定向。
1.3dup2
查看dup2文档可以看到:
这个接口就是来处理上面的情况,它将一个文件描述符表的oldfd的内容拷贝到newfd的位置,实现重定向,代码如下:
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include<stdlib.h>
const char *filename="test.txt";
int main()
{
int fd=open("test.txt",O_CREAT|O_WRONLY|O_TRUNC,0666);
if(fd<0)
{
perror("open\n");
return 1;
}
dup2(fd,1);
printf("printf fd: %d\n",fd);
fprintf(stdout,"fprintf fd: %d\n",fd);
close(fd);
return 0;
}
运行结果为:
1.4标准错误重定向
在c语言中输出错误信息可以通过perror进行输出,可以通过重定向将错误信息和打印信息进行分离,先看代码:
#include<stdio.h>
int main()
{
perror("I am perror\n");
perror("I am perror\n");
perror("I am perror\n");
printf("I am parentf\n");
printf("I am parentf\n");
printf("I am parentf\n");
return 0;
}
直接运行可以看到:
输入下面指令:
./a.out 1>test.txt
结果如下:
可以这样将错误信息进行分离,当然将1改为2会将错误信息重定向到test.txt中。如何向让这俩 重定向到不同外文件中输入指令:
./a.out 1>test1.txt 2>test2.txt
想让这俩重定向到同一个文件输入指令:
./a.out 1>test.txt 2>&1
二.缓冲区
2.1刷新策略
缓冲区是什么?缓冲区就是一段内存空间,缓冲区可以提高使用者的效率,使用者只需要将内容写道缓冲区即可,其余的事情不需要使用者管了,操作系统会自动进行,缓冲区有用户级缓冲区,还有内核级缓冲区。缓冲区的刷新策略有三种,第一种立即刷新(fflush等接口);第二种按行刷新(显示器,主要是为了照顾使用者的使用习惯),第三种全刷新(普通文件)。
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include<stdlib.h>
int main()
{
printf("hello print\n");
fprintf(stdout,"hello fprint\n");
const char*mes="hello write\n";
write(1,mes,strlen(mes));
fork();
return 0;
}
当文件生成可执行程序myfile,输入下面指令:
./myfile > test.txt
查看test.txt内容
这是重定向到普通文件,普通文件刷新策略是全缓冲,而子进程会继承父进程的代码和数据,所以缓冲区了也会继承,所以会有两份,由于write是直接写入所以没有继承。
2.2封装一下库
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SIZE 1024
struct my_FILE
{
int _fileno;
int _flag;
char _buff[SIZE];
int _pos;
int _size;
};
typedef struct my_FILE my_FILE;
my_FILE* my_fopen(const char *pathname, const char *mode);
void my_fflush(my_FILE* fp);
size_t my_write(my_FILE* fp,const char* messag,size_t len);
int my_read(my_FILE* fp,char*data,int len);
void my_fclose(my_FILE *fp);
#include"mystdio.h"
my_FILE* my_fopen(const char *pathname, const char *mode)
{
int fd=0;
int flag=0;
int creat=0;
if(strcmp(mode,"w")==0)
{
flag=O_CREAT|O_WRONLY|O_TRUNC;
creat=1;
}
else if(strcmp(mode,"a")==0)
{
flag=O_APPEND|O_CREAT|O_WRONLY;
creat=1;
}
else if(strcmp(mode,"r")==0)
{
flag=O_RDONLY;
}
else
{
return NULL;
}
if(creat)
{
fd=open(pathname,flag,0666);
}
else
{
fd=open(pathname,flag);
}
if(fd<0) return NULL;
my_FILE* fp= (my_FILE*)malloc(sizeof(my_FILE));
fp->_fileno=fd;
fp->_flag=1;
fp->_pos=0;
fp->_size=0;
return fp;
}
void my_fflush(my_FILE* fp)
{
write(fp->_fileno,fp->_buff,fp->_pos);
fp->_pos=0;
}
size_t my_write(my_FILE* fp,const char* messag,size_t len)
{
memcpy(fp->_buff+fp->_pos,messag,len);
fp->_pos+=len;
fp->_size+=len;
if(fp->_flag==1&&fp->_buff[fp->_pos-1]=='\n')
{
my_fflush(fp);
}
return fp->_pos;
}
int my_read(my_FILE* fp,char*data,int len)
{
return read(fp->_fileno,data,len);
}
void my_fclose(my_FILE *fp)
{
my_fflush(fp);
close(fp->_fileno);
free(fp);
}
#include"mystdio.h"
int main()
{
my_FILE* fp=my_fopen("log.txt","w");
if(fp==NULL)
{
perror("my_fopen\n");
return 1;
}
// char* mes="hello file\n";
// my_write(fp,mes,strlen(mes));
// my_write(fp,mes,strlen(mes));
// my_write(fp,mes,strlen(mes));
// my_write(fp,mes,strlen(mes));
// my_write(fp,mes,strlen(mes));
// my_write(fp,mes,strlen(mes));
// char mes[SIZE];
// int n=my_read(fp,mes,sizeof(mes));
// mes[n]='\0';
// printf("%s\n",mes);
my_fclose(fp);
return 0;
}
可以进行文件的写入和读取。