一、重谈文件
二、回顾C语言文件操作
1.文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。若打开成功,返回文件指针;若打开失败,返回NULL。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
FILE * fopen ( const char * filename, const char * mode );
int fclose ( FILE * stream );
2.读写文件
🚀写文件
文件输出有许多函数,就不一一赘述,常用的是fprintf
fprintf是将特定的数据格式化到特定的文件流中
🚀读文件
fgets从特定文件流中按行读取到缓冲区中
3.关于stdin stdout stderr
文件的输入输出,实际上便是在与硬件进行交互;而有三个标准流,会随着计算机系统的开启而默认打开:
- stdout —— 标准输出流 —— 显示器
- stdin —— 标准输入流 —— 键盘
- stderr —— 标准错误流 —— 显示器
IO的意思是:输入(input)和输出(output),具体来说是外部设备和内存之间的输入输出
💭而上面的三种流属于IO中的外部设备,而在Linux操作系统中,一切皆文件
所以这三个标准流的类型都是 FILE*
三、系统IO
💭 系统IO是什么?为何要学?
我们知道,文件存在与磁盘中,而磁盘是硬件,那要访问硬件需要通过谁?——操作系统
所以我们进行文件操作不能绕开OS,因此OS也提供了文件级别的系统调用接口🎯
而我们平时使用的C语言、C++、JAVA…这些上层语言的文件操作接口,这些语言级别的文件操作接口都不相同,但是不论如何,库函数的底层都是调用系统调用接口;也就是说,这些各式语言级别的文件操作接口,其实都是基于系统调用接口去封装而成的。
因此为了降低学习成本,更深刻地了解IO,我们便从最底层的系统IO入手
1.open & close
📚我们可以通过手册查找具体用法:man 2 open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
✏️参数说明
pathname: 要打开或创建的目标文件文件名
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
🚩返回值说明
成功:新打开的文件描述符
失败:-1
💭文件描述符是什么?我们下文再细说
📚man 2 close
#include <unistd.h>
int close(int fd);
🎯1.open接口的第二个参数原理介绍
我们在写程序的过程中,很经常会用到标记位flags。一般用一个整数(0或1)作为标记位,表示某一件事发生了或作为返回值返回。
一个标记位代表一件事,传一个整数;那10个呢?搞10个参数?太麻烦了吧💤
而我们知道,一个整数是有32个比特位,意味着我们可以通过比特位来传递选项,不同比特位我们自己定义不同的含义
因为我们是按照比特位传递选项,所以势必有要求:1.一个比特位表示一个选项 2.比特位位置不能重复
#include <stdio.h>
#define ONE 0x1
#define TWO 0x2
#define THREE 0x4
#define FOUR 0x8
void show(int flags)
{
if(flags & ONE) printf("one\n");
if(flags & TWO) printf("two\n");
if(flags & THREE) printf("three\n");
if(flags & FOUR) printf("four\n");
}
int main()
{
show(ONE);
printf("----------\n");
show(TWO);
printf("----------\n");
show(ONE