✨个人主页: 熬夜学编程的小林
💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】
目录
1、封装简单的库
1.1、定义文件结构
1.2、打开文件
1.3、刷新缓冲区
1.4、写文件
1.5、关闭文件
1.6、各文件代码
2、stderr
2.1、C语言代码演示
2.2、C++代码演示
1、封装简单的库
1.1、定义文件结构
#define LINE_SIZE 1024
#define FLUSH_NOW 1 // 立即刷新
#define FLUSH_LINE 2 // 行刷新
#define FLUSH_FULL 4 // 全缓冲typedef struct _myFILE
{unsigned int flags;// 文件刷新方式int fileno;// fd// 缓冲区char cache[LINE_SIZE];int cap;// 容量int pos;// 下次写入的位置
}myFILE;// C语言创建结构体变量需要加struct关键字,因此使用typedef重命名
1.2、打开文件
打开文件本质是开辟一块存放文件数据的空间。
myFILE* my_fopen(const char* path,const char* flag)
{int flag1 = 0;// 系统调用的文件打开方式int iscreate = 0;// 文件是否被创建mode_t mode = 0666;// 默认权限设置// 读方式打开文件,只需设置flag1if(strcmp(flag,"r") == 0){flag1 = O_RDONLY;}// 写方式打开文件,设置flag1 和 iscreateelse if(strcmp(flag,"w") == 0){flag1 = (O_WRONLY | O_CREAT | O_TRUNC);iscreate = 1;}// 追加方式打开文件else if(strcmp(flag,"a") == 0){flag1 = (O_WRONLY | O_CREAT | O_APPEND);iscreate = 1;}else {}int fd = 0;if(iscreate)fd = open(path,flag1,mode);// 创建新文件权限限制才有效,传三个参数else fd = open(path,flag1);// 打开已经存在的文件不会修改文件权限,使用两个参数即可if(fd < 0) return NULL;// 打开文件失败返回NULL// 堆区开辟的空间出了函数不会销毁myFILE* fp = (myFILE*)malloc(sizeof(myFILE));if(fp == NULL) return NULL;fp->fileno = fd;fp->flags = FLUSH_LINE;// 设置行刷新fp->cap = LINE_SIZE;fp->pos = 0;return fp;
}
1.3、刷新缓冲区
刷新缓冲区实质是将缓冲区内容写入需要刷新的文件中。
void my_fflush(myFILE* fp)
{// 将缓冲区 pos 个字节的内容写入 fp 的文件中,并将pos置0write(fp->fileno,fp->cache,fp->pos);fp->pos = 0;
}
1.4、写文件
写文件的本质是将内容拷贝到缓冲区中,条件允许就刷新缓冲区。
ssize_t my_fwrite(myFILE* fp,const char* data,int len)
{// 写入的本质是拷贝,条件允许就刷新memcpy(fp->cache + fp->pos ,data,len);// 需要考虑扩容与越界问题,此处不做处理,从简fp->pos += len;// 刷新方式为行刷新且缓冲区遇到\n就刷新缓冲区if((fp->flags & FLUSH_LINE) && fp->cache[fp->pos-1] == '\n'){my_fflush(fp);}return len;
}
1.5、关闭文件
先刷新缓冲区,在关闭文件并释放空间。
void my_fclose(myFILE* fp)
{my_fflush(fp);// 刷新缓冲区close(fp->fileno);// 关闭文件free(fp);// 释放空间
}
1.6、各文件代码
mystdio.h
#pragma once #include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define LINE_SIZE 1024
#define FLUSH_NOW 1
#define FLUSH_LINE 2
#define FLUSH_FULL 4typedef struct _myFILE
{unsigned int flags;int fileno;// 缓冲区char cache[LINE_SIZE];int cap;// 容量int pos;// 下次写入的位置
}myFILE;myFILE* my_fopen(const char* path,const char* flag);
void my_fflush(myFILE* fp);
ssize_t my_fwrite(myFILE* fp,const char* data,int len);
void my_fclose(myFILE* fp);
mystdio.c
#include "mystdio.h"myFILE* my_fopen(const char* path,const char* flag)
{int flag1 = 0;int iscreate = 0;mode_t mode = 0666;if(strcmp(flag,"r") == 0){flag1 = O_RDONLY;}else if(strcmp(flag,"w") == 0){flag1 = (O_WRONLY | O_CREAT | O_TRUNC);iscreate = 1;}else if(strcmp(flag,"a") == 0){flag1 = (O_WRONLY | O_CREAT | O_APPEND);iscreate = 1;}else {}int fd = 0;if(iscreate)fd = open(path,flag1,mode);else fd = open(path,flag1);if(fd < 0) return NULL;myFILE* fp = (myFILE*)malloc(sizeof(myFILE));if(fp == NULL) return NULL;fp->fileno = fd;fp->flags = FLUSH_LINE;fp->cap = LINE_SIZE;fp->pos = 0;return fp;
}
void my_fflush(myFILE* fp)
{write(fp->fileno,fp->cache,fp->pos);fp->pos = 0;
}
ssize_t my_fwrite(myFILE* fp,const char* data,int len)
{// 写入的本质是拷贝,条件允许就刷新memcpy(fp->cache + fp->pos ,data,len);// 考虑扩容与越界问题fp->pos += len;if((fp->flags&FLUSH_LINE) && fp->cache[fp->pos-1] == '\n'){my_fflush(fp);}return len;
}
void my_fclose(myFILE* fp)
{my_fflush(fp);close(fp->fileno);free(fp);
}
testfile.c
#include "mystdio.h"
#include <stdio.h>#define FILENAME "log.txt"int main()
{// 使用自己封装的函数以写方式打开文件myFILE* fp = my_fopen(FILENAME,"w");if(fp == NULL) return 1;const char* str = "hello linux";int cnt = 10;char buff[128];while(cnt){// 将格式化数据转成字符串到buff中sprintf(buff,"%s - %d",str,cnt);// 将buff写入文件my_fwrite(fp,buff,strlen(buff));cnt--;sleep(1);my_fflush(fp);// 写完一组数据就刷新缓冲区}my_fclose(fp);// 关闭文件return 0;
}
运行结果
2、stderr
2.1、C语言代码演示
#include <stdio.h>int main()
{perror("error:");fprintf(stdout,"hello fprintf stdout\n");fprintf(stderr,"hello fprintf stderr\n");return 0;
}
看现象
我们可以看到一部分数据存入了文件中,但是一部分数据没有存入文件中。
实质是 > 是标准输出重定向,修改1号fd里面的内容,其余的是2号fd里面的内容,因此直接打印到显示器上。
为什么有了标准输出流还要有标准错误流呢???
因为我们在编写程序的时候不能保证一直都是正确的代码,当我们查错误的时候就可以通过标准错误流查询。标准输出流主要用于程序的正常输出信息,标准错误流则用于输出程序的错误信息,两者共同确保了程序的运行状态可以被正确地监控和理解。
如果想让2和1都重定向到文件中怎么做?
1、将数据存入不同的文件
将1号的内容重定向到ok.txt 文件,将2号的内容存入err.txt文件。
命令行代码
[jkl@host file3]$ ./a.out
error:: Success
hello fprintf stdout
hello fprintf stderr
[jkl@host file3]$ ./a.out 1>ok.txt 2>err.txt
[jkl@host file3]$ cat ok.txt
hello fprintf stdout
[jkl@host file3]$ cat err.txt
error:: Success
hello fprintf stderr
运行结果
2、将数据存入同一个文件
命令行代码
[jkl@host file3]$ ./a.out 1>all.txt 2>&1
[jkl@host file3]$ cat all.txt
error:: Success
hello fprintf stderr
hello fprintf stdout
运行结果
总结
- perror("open");本质是向2号打印。
- printf("");本质是向1号打印。
2.2、C++代码演示
#include <iostream>int main()
{std::cout<<"hello cout"<<std::endl;std::cerr<<"hello cerr"<<std::endl;return 0;
}
命令行代码
[jkl@host file3]$ g++ test_stderr.cpp
[jkl@host file3]$ ./a.out
hello cout
hello cerr
[jkl@host file3]$ ./a.out > log.txt
hello cerr
[jkl@host file3]$ cat log.txt
hello cout
运行结果