目录
一、回顾C文件
文件 = 内容 + 属性
- 对文件的操作:a.对内容操作 b.对属性操作
- 内容是数据,属性其实也是数据 —— 存储文件,必须既存储内容,又存储属性数据 —— 默认文件是在磁盘中的。
- 要访问一个文件的时候,要先把这个文件打开。
把含有打开文件的代码(fopen)编译成可执行程序,并将程序运行起来,在执行fopen函数时才会打开这个文件。进程是Linux中最常见的文件打开者。 - 文件打开前,是普通的磁盘文件。打开后,文件被加载到内存。
- 一个进程可以打开多个文件、多个进程可以打开多个文件。加载到内存中被打开的文件,可能会存在多个。
- 加载磁盘上的文件,一定会涉及到磁盘设备,该操作由OS执行。
- 操作系统在运行中,可能会打开很多个文件,也需要管理很多文件,就需要“先描述再组织”
- 一个文件要被打开,一定要先在内核中形成被打开的文件对象,该对象包含文件的很多属性。例如 struct file
- 于是对打开文件的管理,就变成了对链表的增删查改。
- 对文件管理的学习,就要研究被打开的文件在内存中的表现,和没有被打开的文件在磁盘中如何存储。
fopen函数
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
参数:
- filename:指向包含文件路径的字符串指针。
- mode:指向包含文件打开模式的字符串指针。
文件打开模式:
- r:以读取方式打开文件,文件必须存在。
- w:以写入方式打开文件,如果文件已存在,会将文件长度截断成0,从文件开头处写入;文件不存在则创建文件。类似echo "..." > log.txt
- a:以追加方式打开文件,写入数据将添加到文件末尾。类似echo "..." >> log.txt
- +:允许读写文件。
- b:以二进制模式打开文件(通常用于非文本文件)。
- t:以文本模式打开文件(默认模式)。
二、系统文件I/O
综上所述,文件是在磁盘中的,要被访问就要先被打开,打开文件的本质是将文件加载到内存里,加载的过程由操作系统完成,因此一个进程需要通过操作系统打开文件。操作系统管理硬件,会提供许多系统调用接口。C语言打开文件的接口,底层一定封装了系统调用接口。
w 和 a 方式打开文件,底层调用的就是open。
2.1 系统调用 open
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:标志位,指定打开文件的选项。
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写。
O_TRUNC:如果文件已存在,则截断文件内容。- mode:指定文件权限的模式,仅在 O_CREAT 标志被设置时使用。
返回值:
- 文件成功打开,返回一个非负整数的文件描述符。
- 文件打开失败,返回 -1,并且可以通过 errno 获取错误信息。
注:
- open 函数具体使用哪个,和具体应用场景相关。如目标文件不存在,需要open创建,此时第三个参数表示创建文件的默认权限,否则使用两个参数的open。
- open 创建打开文件时如果flags设置为O_WRONLY | O_CREAT | O_TRUNC,且没有设置mode权限,文件被创建为具有默认权限的文件,通常是 0644。
- 创建文件时,权限为:mode & ~umask(权限掩码),可使用系统调用umask()设置文件创建时的权限掩码。可以直接设置umask(0),这样设置的mode就是新创建文件的权限。但是这种方法不推荐,推荐使用系统默认的umask。
#include <sys/types.h>
#include <sys/stat.h>mode_t umask(mode_t mask);
fopen的w方式打开相当于open选项的O_WRONLY | O_CREAT |