前篇已经讲过open打开文件的操作使用,本篇文章介绍剩余的wirte、read、close、lseek等操作。
1.write写文件
调用 write 函数可向打开的文件写入数据,其函数原型如下所示(可通过"man 2 write"查看):
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
首先使用 write 函数需要先包含 unistd.h 头文件。
函数参数和返回值含义如下:
**fd:**文件描述符。关于文件描述符,前面已经给大家进行了简单地讲解,这里不再重述!我们需要将进行写操作的文件所对应的文件描述符传递给 write 函数。
**buf:**指定写入数据对应的缓冲区。
**count:**指定写入的字节数。
**返回值:**如果成功将返回写入的字节数(0 表示未写入任何字节),如果此数字小于 count 参数,这不是错误,譬如磁盘空间已满,可能会发生这种情况;如果写入出错,则返回-1。
对于普通文件(我们一般操作的大部分文件都是普通文件,譬如常见的文本文件、二进制文件等),不管是读操作还是写操作,一个很重要的问题是:从文件的哪个位置开始进行读写操作?也就是 IO 操作所对应的位置偏移量,读写操作都是从文件的当前位置偏移量处开始,当然当前位置偏移量可以通过 lseek 系统调用进行设置,关于此函数后面再讲;默认情况下当前位置偏移量一般是 0,也就是指向了文件起始位置,当调用 read、write 函数读写操作完成之后,当前位置偏移量也会向后移动对应字节数,譬如当前位置偏移量为 1000 个字节处,调用 write()写入或 read()读取 500 个字节之后,当前位置偏移量将会移动到 1500 个字当调用 read、write 函数读写操作完成之后,当前位置偏移量也会向后移动对应字节数,譬如当前位置偏移量为 1000 个字节处,调用 write()写入或 read()读取 500 个字节之后,当前位置偏移量将会移动到 1500 个字节处。
2.read读文件
调用 read 函数可从打开的文件中读取数据,其函数原型如下所示(可通过"man 2 read"查看):
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
首先使用 read 函数需要先包含 unistd.h 头文件。
函数参数和返回值含义如下:
**fd:**文件描述符。与 write 函数的 fd 参数意义相同。
**buf:**指定用于存储读取数据的缓冲区。**count:**指定需要读取的字节数。
**返回值:**如果读取成功将返回读取到的字节数,实际读取到的字节数可能会小于 count 参数指定的字节数,也有可能会为 0,譬如进行读操作时,当前文件位置偏移量已经到了文件末尾。实际读取到的字节数少于要求读取的字节数,譬如在到达文件末尾之前有 30 个字节数据,而要求读取 100 个字节,则 read 读取成功只能返回 30;而下一次再调用 read 读,它将返回 0(文件末尾)
3. close关闭文件
可调用 close 函数关闭一个已经打开的文件,其函数原型如下所示(可通过"man 2 close"查看):
#include <unistd.h>int close(int fd);
首先使用 close 函数需要先包含 unistd.h 头文件,当我们对文件进行 IO 操作完成之后,后续不再对文件进行操作时,需要将文件关闭。
函数参数和返回值含义如下:
**fd:**文件描述符,需要关闭的文件所对应的文件描述符。
**返回值:**如果成功返回 0,如果失败则返回-1。
除了使用 close 函数显式关闭文件之外,在 Linux 系统中,当一个进程终止时,内核会自动关闭它打开的所有文件,也就是说在我们的程序中打开了文件,如果程序终止退出时没有关闭打开的文件,那么内核会自动将程序中打开的文件关闭。很多程序都利用了这一功能而不显式地用 close 关闭打开的文件。
显式关闭不再需要的文件描述符往往是良好的编程习惯,会使代码在后续修改时更具有可读性,也更可靠,进而言之,文件描述符是有限资源,当不再需要时必须将其释放、归还于系统。
4. lseek读写指针位置
对于每个打开的文件,系统都会记录它的读写位置偏移量,我们也把这个读写位置偏移量称为读写偏移量,记录了文件当前的读写位置,当调用 read()或 write()函数对文件进行读写操作时,就会从当前读写位置偏移量开始进行数据读写。
读写偏移量用于指示 read()或 write()函数操作时文件的起始位置,会以相对于文件头部的位置偏移量来表示,文件第一个字节数据的位置偏移量为 0。
当打开文件时,会将读写偏移量设置为指向文件开始位置处,以后每次调用 read()、write()将自动对其进行调整,以指向已读或已写数据后的下一字节,因此,连续的调用 read()和 write()函数将使得读写按顺序递增,对文件进行操作。我们先来看看 lseek 函数的原型,如下所示(可通过"man 2 lseek"查看):
#include <sys/types.h>
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
首先调用 lseek 函数需要包含<sys/types.h>和<unistd.h>两个头文件。
函数参数和返回值含义如下:
**fd:**文件描述符。
**offset:**偏移量,以字节为单位。
**whence:**用于定义参数 offset 偏移量对应的参考值,该参数为下列其中一种(宏定义):
- SEEK_SET:读写偏移量将指向 offset 字节位置处(从文件头部开始算);
- SEEK_CUR:读写偏移量将指向当前位置偏移量 + offset 字节位置处,offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移;
- SEEK_END:读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。
**返回值:**成功将返回从文件头部开始算起的位置偏移量(字节为单位),也就是当前的读写位置;发生错误将返回-1。
使用示例:
- 将读写位置移动到文件开头处:
off_t off = lseek(fd, 0, SEEK_SET);
if (-1 == off)return -1;
- 将读写位置移动到文件末尾:
off_t off = lseek(fd, 0, SEEK_END);if (-1 == off)return -1;
- 将读写位置移动到偏移文件开头 100 个字节处:
off_t off = lseek(fd, 100, SEEK_SET);if (-1 == off)return -1;
- 获取当前读写位置偏移量:
off_t off = lseek(fd, 0, SEEK_CUR);
if (-1 == off)return -1;
函数执行成功将返回文件当前读写位置