每一个 FILE 文件流都有一个缓冲区 buffer,默认大小 8192Byte。
事实上 Unbuffered I/O 这个名词是有些误导的,虽然 write 系统调用位于 C 标准库 I/O 缓 冲区的底层,但在 write 的底层也可以分配一个内核 I/O 缓冲区,所以 write 也不一定是直接 写到文件的,也可能写到内核 I/O 缓冲区中,至于究竟写到了文件中还是内核缓冲区中对于 进程来说是没有差别的,如果进程 A 和进程 B 打开同一文件,进程 A 写到内核 I/O 缓冲区中的数 据从进程 B 也能读到,而 C 标准库的 I/O 缓冲区则不具有这一特性(想一想为什么)。
/usr/src/linux-headers/include/linux/sched.h
复制代码
一个进程默认打开 3 个文件描述符
STDIN_FILENO 0 STDOUT_FILENO 1 STDERR_FILENO 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); 返回值:成功返回新分配的文件描述符,出错返回-1并设置errno
复制代码
在 Man Page 中 open 函数有两种形式,一种带两个参数,一种带三个参数,其实在 C 代码 中 open 函数是这样声明的:
int open(const char *pathname, int flags, ...);
复制代码
最后的可变参数可以是 0 个或 1 个,由 flags 参数中的标志位决定,见下面的详细说明。
pathname 参数是要打开或创建的文件名,和 fopen 一样,pathname 既可以是相对路径也 可以是绝对路径。flags 参数有一系列常数值可供选择,可以同时选择多个常数用按位或运 算符连接起来,所以这些常数的宏定义都以 O_开头,表示 or。
必选项:以下三个常数中必须指定一个,且仅允许指定一个。
复制代码
* O_RDONLY 只读打开* O_WRONLY 只写打开* O_RDWR 可读可写打开
以下可选项可以同时指定 0 个或多个,和必选项按位或起来作为 flags 参数。可选项有很多, 这里只介绍一部分,其它选项可参考 open(2)的 Man Page:
$ umask 0002
复制代码
用 touch 命令创建一个文件时,创建权限是 0666,而 touch 进程继承了 Shell 进程的 umask 掩码,所以最终的文件权限是 0666&∼022=0644。
$ touch file123 $ ls -l file123 -rw-rw-r-- 1 qingkouwei qingkouwei 0 9月 11 23:48 file123
复制代码
同样道理,用 gcc 编译生成一个可执行文件时,创建权限是 0777,而最终的文件权限是
0777 & ∼022 = 0755。
ubuntu:~$ umask 0002 ubuntu:~$ gcc main.c ubuntu:~$ ls -l a.out -rwxrwxr-x 1 qingkouwei qingkouwei 7158 9月 11 23:51 a.out
复制代码
我们看到的都是被 umask 掩码修改之后的权限,那么如何证明 touch 或 gcc 创建文件的权 限本来应该是 0666 和 0777 呢?我们可以把 Shell 进程的 umask 改成 0,再重复上述实验:
$ rm file123 a.out $ umask 0 $ touch file123 $ ls -l file123 -rw-rw-rw- 1 qingkouwei qingkouwei $ gcc main.c 0 9月 11 23:52 file123 $ ls -l a.out -rwxrwxr-x 1 qingkouwei qingkouwei 7158 9月 11 23:52 a.out
复制代码
现在我们自己写一个程序,在其中调用 open(“somefile”, O_WRONLY | O_CREAT, 0664);创建文件,然后在 Shell 中运行并查看结果:
close 函数关闭一个已打开的文件:
#include <unistd.h> int close(int fd); 返回值:成功返回0,出错返回-1并设置errno
复制代码
参数 fd 是要关闭的文件描述符。需要说明的是,当一个进程终止时,内核对该进程所有 尚未关闭的文件描述符调用 close 关闭,所以即使用户程序不调用 close,在终止时内核也会 自动关闭它打开的所有文件。但是对于一个长年累月运行的程序(比如网络服务器),打开 的文件描述符一定要记得关闭,否则随着打开的文件越来越多,会占用大量文件描述符和系 统资源。
由 open 返回的文件描述符一定是该进程尚未使用的最小描述符。由于程序启动时自动打 开文件描述符 0、1、2,因此第一次调用 open 打开文件通常会返回描述符 3,再调用 open 就会 返回 4。可以利用这一点在标准输入、标准输出或标准错误输出上打开一个新文件,实现重 定向的功能。例如,首先调用 close 关闭文件描述符 1,然后调用 open 打开一个常规文件, 则一定会返回文件描述符 1,这时候标准输出就不再是终端,而是一个常规文件了,再调用 printf 就不会打印到屏幕上,而是写到这个文件中了。后面要讲的 dup2 函数提供了另外一种 办法在指定的文件描述符上打开文件。
查看当前系统允许打开最大文件个数
cat /proc/sys/fs/file-max
复制代码
当前默认设置最大打开文件个数 1024
ulimit -a
复制代码
修改默认设置最大打开文件个数为 4096
ulimit -n 4096
复制代码
文本介绍了 Linux 下的文件操作命令、系统调用、API 接口等。并介绍了 C 标准函数与系统函数的区别,PCB 概念等。
领取专属 10元无门槛券
私享最新 技术干货