APUE编程:14---文件I/O之(文件共享、文件原子操作(pread()、pwrite()))
原创
©著作权归作者所有:来自51CTO博客作者董哥的黑板报的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、文件共享
文件的打开
-
每个进程打开文件时,一般有三项:
- ①进程表项中的一个进程指向于一个文件表项
- ②每个进程都有一个属于自己的文件标项
- ③文件表项的节点指针指向于真实的文件
文件共享
-
概念:我们知道一个文件可以被多个不同的进程同时打开
- 例如:两个不同的进程打开同一个文件
- 先用文件指针打开自己的文件表项
- 然后通过文件表项的节点指针指向于文件真实内容
二、原子操作
open()函数的O_APPEND参数介绍
- 如果我们要将数据追加到一个文件尾端。早起的UNIX系统并不支持O_APPEND参数,会用以下的代码实现 (每次写入之前都使用lseek函数来指定文件指针的偏移量)
if (lseek(fd, 0L, 2) < 0) /*position to EOF*/
perror("lseek error");
if (write(fd, buff, 100) != 100) /*and write*/
perror("write error");
-
上面代码的弊端:如果我们有两个进程同时对这个文件进行写入。A进程使用lseek对文件的1500字节进行写入,B进程也使用lseek对文件的1500字节进行写入。本来AB进程的目的都是想在文件的尾端进行写入,如果此时某个进程先执行,那么文件的内容增加,另外一个内容再去写入时就不会在尾端写入了,而是插入写入
-
原子操作:上面代码弊端的逻辑操作是“”先定位到文件尾端,再写入“,使得两个函数分开调用,这样会产生错误。UXIX就提供了O_APPEND这个原子操作,在逻辑上综合了上面先lseek再write的操作,就是每次在写入时都追加写入,这样每次尾追写入就不需要调用fseek函数了
open()函数的O_CREAT和O_EXCL参数介绍
- 如果我们判断一个文件是否存在,如果不存在就创建这个文件,可能会建立下面的代码
if ((fd = open(pathname, O_WRONLY)) <0)
{
if (errno == ENOENT)
{
if ((fd = creat(pathname, mode)) < 0)
err_sys("creat error");
}
else
err_sys("open error");
}
-
上面代码的弊端:如果一个进程打开这个文件不存在正要去创建它时,突然另一个进程提前创建了它,那么就会出现问题,这段程序的creat就会将另一个进程写入的数据擦去
-
原子操作:open()函数提供O_CREAT和O_EXCL这两个参数配合使用,如果去创建文件但文件已存在就会open()失败
pread()、pwrite()
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
//参数4:文件起始的偏移量
//返回值:成功返回读到的字节数;若达到文件尾,返回0;出错,返回-1
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
//参数4:文件起始的偏移量
//返回值:成功返回写入的字节数;出错,返回-1
- 这两个函数允许原子性地定位并执行I/O
- 这两个函数免去了先调用fseek再read/write,将这两个步骤结合在一起
-
pread相当于调用lseek后调用read,特点如下:
- 调用pread时,无法中断其定位和读操作
- 不更新当前文件偏移量
- pwrite相当于调用lseek后调用write,特点同上
原子操作概念
- 原子操作指的是原本多部才能达到目的的操作结合为一个操作
- 如果该操作原子地执行,要么执行完所有的步骤,要么一步也不执行,不可能只执行所有步骤中的一个子集