代码仓库地址:https://gitee.com/tgwTTT/linux-learning-dai/tree/master/glibc
文件:
1.狭义理解:
• ⽂件在磁盘⾥
• 磁盘是永久性存储介质,因此⽂件在磁盘上的存储是永久性的
• 磁盘是外设(即是输出设备也是输⼊设备)
• 磁盘上的⽂件 本质是对⽂件的所有操作,都是对外设的输⼊和输出 简称 IO
2.广义理解:
Linux 下⼀切皆⽂件(键盘、显⽰器、⽹卡、磁盘…… 这些都是抽象化的过程)
3.文件特点:
• 对于 0KB 的空⽂件是占⽤磁盘空间的 •
⽂件是⽂件属性(元数据)和⽂件内容的集合(⽂件 = 属性(元数据)+ 内容)
• 所有的⽂件操作本质是⽂件内容操作和⽂件属性操作
下面以c文件接口为例去介绍IO
c文件接口:
fwrite()

fread()

除此之外会默认打开三个输⼊输出流stdin & stdout & stderr
接下来是linux系统IO接口介绍
打开⽂件的⽅式不仅仅是fopen,ifstream等流式,语⾔层的⽅案,其实系统才是打开⽂件最底层的⽅案。不过,在学习系统⽂件IO之前,先要了解下如何给函数传递标志位,该⽅法在系统⽂件IO接⼝中会使⽤到:
例如这种方式:
#include
#define ONE 0001 //0000 0001
#define TWO 0002 //0000 0010
#define THREE 0004 //0000 0100
void func(int flags) {
if (flags & ONE) printf("flags has ONE! ");
if (flags & TWO) printf("flags has TWO! ");
if (flags & THREE) printf("flags has THREE! ");
printf("\n");
}
int main() {
func(ONE);
func(THREE);
func(ONE | TWO);
func(ONE | THREE | TWO);
return 0;
}
open函数:

pathname: 要打开或创建的⽬标⽂件
flags: 打开⽂件时,可以传⼊多个参数选项,⽤下⾯的⼀个或者多个常量进⾏“或”运算,构成flags。
write函数:

文件描述符fd
文件数组buf
大小count
下面是用系统函数调用实现c库中的函数
#include
#include
#include
#include
#include
// 刷新方式
#define LINE_FLUSH 0x1
// 自定义 FILE 结构
struct MYFILE {
int fileno; // 文件描述符
int flag; // 打开标志
int bufferlen; // 缓冲区中已用字节数
char outbuffer[1024]; // 输出缓冲区
int flush_method; // 刷新策略
};
// 创建并初始化 MYFILE 对象
static MYFILE* BuyFile(int fd, int flag) {
MYFILE* f = new MYFILE();
if (f == nullptr) return nullptr;
f->bufferlen = 0;
f->fileno = fd;
f->flag = flag;
f->flush_method = LINE_FLUSH;
memset(f->outbuffer, 0, sizeof(f->outbuffer));
return f;
}
// 自定义 fopen
MYFILE* MYFopen(const char* path, const char* mode) {
int fd = -1;
int flag = 0;
if (strcmp(mode, "w") == 0) {
flag = O_CREAT | O_WRONLY | O_TRUNC;
fd = open(path, flag, 0666);
}
else if (strcmp(mode, "a") == 0) {
flag = O_CREAT | O_WRONLY | O_APPEND;
fd = open(path, flag, 0666);
}
else if (strcmp(mode, "r") == 0) {
flag = O_RDONLY;
fd = open(path, flag);
}
else {
// 非法模式
return nullptr;
}
if (fd < 0) return nullptr;
return BuyFile(fd, flag);
}
// 自定义 fclose
void MYFclose(MYFILE* file) {
if (file) {
MYFflush(file); // 关闭前刷新
close(file->fileno);
delete file;
}
}
// 自定义 fflush
void MYFflush(MYFILE* file) {
if (file == nullptr || file->bufferlen == 0) return;
ssize_t n = write(file->fileno, file->outbuffer, file->bufferlen);
if (n < 0) {
perror("write failed");
}
file->bufferlen = 0;
}
// 自定义 fwrite
int MYFwrite(MYFILE* file, const void* str, int len) {
if (file == nullptr || str == nullptr || len <= 0) return 0;
// 如果缓冲区装不下,先刷新
if (file->bufferlen + len > (int)sizeof(file->outbuffer)) {
MYFflush(file);
}
// 拷贝到缓冲区
memcpy(file->outbuffer + file->bufferlen, str, len);
file->bufferlen += len;
// 行缓冲:遇到 '\n' 就刷新
if ((file->flush_method & LINE_FLUSH) && file->outbuffer[file->bufferlen - 1] == '\n') {
MYFflush(file);
}
return len;
}
// 测试用例
int main() {
MYFILE* fp = MYFopen("test.txt", "w");
if (!fp) {
perror("MYFopen failed");
return 1;
}
const char* msg1 = "Hello, world!\n";
const char* msg2 = "This is a test.\n";
MYFwrite(fp, msg1, strlen(msg1));
MYFwrite(fp, msg2, strlen(msg2));
MYFclose(fp);
return 0;
}
下面是运行结果:


今天的更新就到这里,如有错误欢迎评论区指出,谢谢
评论
还没有任何评论,你来说两句吧!