系统调用与程序运行空间
在Linux操作系统中,为了提高系统的稳定性,保证内核的安全,程序运行时的内存空间被分为了用户空间和内核空间。普通应用程序工作在用户空间,不能直接访问内核空间。它们需要使用Linux系统提供给用户的一些"特殊接口" - 系统调用来安全地访问内核空间。
文件描述符
在Linux系统中,一切都可以被看作是文件,这包括:普通文件、目录文件、链接文件和设备文件。要访问文件,必须使用文件描述符。文件描述符是一个非负的整数,它是系统中被打开文件的索引。当打开或者创建一个文件时,内核会返回一个文件描述符;当需要读写文件时,也需要将相应的文件描述符作为参数传给读写函数。程序启动时,默认有3个文件描述符:
文件描述符 | 宏 | 说明 |
---|---|---|
0 | STDIN_FILENO | 标准输入 |
1 | STDOUT_FILENO | 标准输出 |
2 | STDOUT_FILENO | 标准错误输出 |
如果此时创建或打开一个文件,这个文件的文件描述符就是3.
文件IO基本操作
打开/创建文件
open()
函数用于打开或者创建文件。其在打开或者创建文件时可以指定文件的属性及用户的权限等各种参数。要使用 open()
函数,需要包含 #include <sys/stat.h>
和 #include <fcntl.h>
这两个头文件。下面是函数的说明:
int open(const char *path, int oflag, [mode_t mode]);
args:
const char *path: 文件路径,可以是绝对,也可以是相对路径
int oflag : 文件打开的方式
- O_RDONLY 只读打开
- O_WRONLY 只写打开
- O_RDWR 可读可写打开
以上3种必选一个,以下4种可以任意选择
- O_APPEND 追加打开,所写数据附加到文件末
- O_CREAT 若此文件不存在则创建它
- O_EXCL 若文件存在则报错返回
- O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断为0字节
[mode_t mode] : 文件权限,只有在创建文件时需要使用
return:
文件描述符,非负整数是成功,-1是失败
在 open()
函数中,文件的打开方式不止上面的几种,这里只列举了常用的7种。注意,新建文件的权限不是直接等于 mode
的值,而是等于 mode & ~uname
。
写文件
当文件打开后,我们就可以向该文件写数据了。在Linux系统中,用 write()
向打开的文件写入数据,要使用这个函数,需要包含 #include <unistd.h>
。下面是函数的说明:
ssize_t write(int fildes, const void *buf, size_t nbyte);
args:
int fildes : 写入文件的文件描述符
const void *buf: 写入数据在内存空间存储的地址
size_t nbyte : 期待写入数据的最大字节数
return:
文件实际写入的字节数,非负整数是成功,-1是失败(磁盘已满或者超出该文件的长度等)
注意函数的返回类型是 ssize_t
。 ssize_t
同 size_t
类似,只是 ssize_t
表示有符号数。想了解更多 size_t
和 ssize_t
的区别请看这篇文章。
读文件
同写文件类似,要使用读文件函数 read()
,需要包含 #include <unistd.h>
。下面是函数的说明:
ssize_t read(int fildes, void *buf, size_t nbyte);
args:
int fildes : 读取文件的文件描述符
void *buf : 读取数据在内存空间存储的地址
size_t nbyte: 期待读取数据的最大字节数
return:
文件实际读取的字节数,非负整数是成功,-1是失败
同 write()
一样, read()
函数的返回类型也是 ssize_t
。
文件的偏移量
在每个打开的文件中都有一个文件的偏移量,文件的偏移量会根据文件的读写而改变位置。我们可以通过 lseek()
函数来调整文件的偏移量。默认情况下,新打开文件的文件偏移量在文件的开始。同 write()
和 read()
函数类似,要使用这个函数,需要包含 #include <unistd.h>
。下面是函数的说明:
off_t lseek(int fildes, off_t offset, int whence);
args:
int fildes : 修改文件的文件描述符
off_t offset: 文件偏移量移动的距离
int whence : 文件偏移量的基址
- SEEK_SET 文件开始处
- SEEK_CUR 文件当前位置
- SEEK_END 文件结束处
return:
当前文件指针的位置,非负整数是成功,-1是失败
off_t
同 ssize_t
类似,都是有符号数。
关闭文件
当文件不再被使用时,可以调用 close()
函数来关闭被打开的文件。
除了用 close()
显示地关闭文件外,通过结束进程也能隐式地关闭被该进程打开的所有文件。要使用该函数,需要包含 #include <unistd.h>
。下面是函数的说明:
int close(int fildes);
args:
int fildes: 要关闭文件的文件描述符
return:
文件关闭状态,0是成功,-1是失败