文章目录
- 一、理解"文件"
- 1、狭义上的理解
- 2、广义上的理解
- 3、文件操作的认知
- 4、系统角度
- 二、C语言文件接口
- 1、ls /proc/[进程id] -l 命令查看当前正在运⾏进程的信息
- 2、stdin 和 stdout 和 stderr
- 三、系统文件 I/O
- 1、标志位传递的一种方法
- 2、系统调用 open
- 三、文件描述符fd
- 1、write 写文件
- 2、read 读文件
- 3、0、1、2 文件描述符
- 4、重定向
- 四、理解“一切皆文件”
- 五、缓冲区
- 1、什么是缓冲区
- 2、为什么要引入缓冲区机制
- 3、缓冲类型
- 4、fsync 将内核缓冲区刷新到外设
- 5、简单设计libc库
一、理解"文件"
1、狭义上的理解
• ⽂件在磁盘⾥
• 磁盘是永久性存储介质,因此⽂件在磁盘上的存储是永久性的
• 磁盘是外设(即是输出设备也是输⼊设备)
• 磁盘上的⽂件 本质是对⽂件的所有操作,都是对外设的输⼊和输出 简称 IO
2、广义上的理解
• Linux 下⼀切皆⽂件(键盘、显⽰器、⽹卡、磁盘…… 这些都是抽象化的过程)
3、文件操作的认知
• 对于 0KB 的空⽂件是占⽤磁盘空间的
• ⽂件是⽂件属性(元数据)和⽂件内容的集合(⽂件 = 属性(元数据)+ 内容)
• 所有的⽂件操作本质是⽂件内容操作和⽂件属性操作
4、系统角度
• 对⽂件的操作本质是进程对⽂件的操作
• 磁盘的管理者是操作系统• ⽂件的读写本质不是通过C语⾔/C++的库函数来操作的(这些库函数只是为⽤⼾提供⽅便),⽽是通过⽂件相关的系统调⽤接来实现的
fopen,fclose…库封装了底层OS的文件系统调用!
二、C语言文件接口
1、ls /proc/[进程id] -l 命令查看当前正在运⾏进程的信息
其中:
- cwd:指向当前进程运⾏⽬录的⼀个符号链接。
- exe:指向启动当前进程的可执⾏⽂件(完整路径)的符号链接。
2、stdin 和 stdout 和 stderr
- C默认会打开三个输⼊输出流,分别是stdin, stdout, stderr
stdin:标准输入 键盘文件
stdout:标准输出 显示器文件
stderr:标准错误 显示器文件
三、系统文件 I/O
1、标志位传递的一种方法
标志位传递的一种方法:
2、系统调用 open
第一个参数带路径,或只写文件名就在当前路径打开文件
flags的选项:表示打开文件的模式,每一个模式都是一个标记位
都是宏替换,每个标志位只有一个比特位为1
mode:权限位,在新建文件时
这里传的mod 参数最终的权限会受到umask的影响
可以通过umask()函数设置当前程序的权限掩码
close()把打开的文件关闭
三、文件描述符fd
1、write 写文件
const void *buf 可以二进制写入和文本写入
第一个参数fd就是open()的返回值,这个返回值叫文件描述符
2、read 读文件
3、0、1、2 文件描述符
Linux进程默认情况下会有3个缺省打开的⽂件描述符,分别是标准输⼊0,标准输出1,标准错误2.
是C语言提供了一个结构体 typedef XXX{…}FILE; 中一定封装了文件描述符fd!!!
4、重定向
更改文件描述符表的指针指向,数组下标不变
李淼换太子实现重定向:
原本标准输出的文件描述符是1,但关闭1后重新把1分配给fd,而printf()打印是标准输出1这个文件里面的,此时输出在log.txt文件中,这种现象就是重定向
- 系统调用进行重定向
int dup2(int oldfd, int newfd);
使newfd成为oldfd的一份拷贝
- 重定向:打开文件的方式+dup2
四、理解“一切皆文件”
通过封装一层驱动软件使得文件指针指向不同的操作实现多态来屏蔽底层设备的差异
五、缓冲区
1、什么是缓冲区
缓冲区是内存空间的⼀部分。也就是说,在内存空间中预留了⼀定的存储空间,这些存储空间⽤来缓冲输⼊或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输⼊设备还是输出设备,分为输⼊缓冲区和输出缓冲区。
2、为什么要引入缓冲区机制
提高使用者的效率
3、缓冲类型
显示器文件写入时:行刷新
普通文件:全缓存,写满时刷新
4、fsync 将内核缓冲区刷新到外设
5、简单设计libc库
my_stdio.h :
#pragma once#include <stdio.h>#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2#define SIZE 1024struct IO_FILE
{int fileno;//文件描述符int flag;//打开文件方式char buffer[SIZE]; //模拟缓冲区int size;//文件大小int flush_mode;//刷新方式
};typedef struct IO_FILE mFILE;mFILE* Myfopen(const char* path,const char* mod);void Myfclose(mFILE* f);void Myfflush(mFILE* f);void Myfwrite(const char* str,int len,mFILE* f);
my_stdio.c
#include "my_stdio.h"
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>mFILE* Myfopen(const char* path,const char* mod)
{int fd = -1;int flag;if(strcmp(mod,"r") == 0){flag = O_RDONLY;fd = open(path,flag);}else if(strcmp(mod,"w") == 0){flag = O_CREAT | O_WRONLY | O_TRUNC;fd = open(path,flag,0666);}else if(strcmp(mod,"a") == 0){flag = O_CREAT | O_WRONLY | O_APPEND; fd = open(path,flag,0666);} else {//...}if(fd < 0)return NULL;mFILE* pf = (mFILE*)malloc(sizeof(mFILE));if(pf == NULL){close(fd);return NULL;}pf->fileno = fd;pf->flag = flag;pf->flush_mode = FLUSH_LINE;pf->size = 0;return pf;
}void Myfflush(mFILE* f)
{write(f->fileno,f->buffer,f->size);f->size = 0;fsync(f->fileno);
}void Myfwrite(const char* str,int len,mFILE* f)
{int j = 0;while(j < len){int i = f->size;for(;i < SIZE && j < len; i++,j++){f->buffer[i] = str[j];}f->size = i;if(i == SIZE){Myfflush(f);}}if(f->flush_mode == FLUSH_LINE && f->buffer[f->size - 1] == '\n'){Myfflush(f);}
}void Myfclose(mFILE* f)
{if(f->size > 0)Myfflush(f);close(f->fileno);free(f);
}