四、文件IO——内核数据结构和原子操作
4.1 缓存 buff 说明
一般设置缓存 buff 的大小是由一定的规律的,就是根据磁盘块的大小来定。
Linux下输入命令: df -k 查看磁盘

可以用命令查看下 /dev/sda1 磁盘的磁盘说明
sudo tune2fs -l /dev/sda1

Block size 就是磁盘块的大小,这个磁盘块的大小为 4M ,那么就可以设置缓存 buff 大小为 4096,一次就可以将数据写入。
设置的缓存大小最好与磁盘块的大小保持一致,有利于提升读写文件的效率。
4.2 操作文件中内核数据结构简要介绍
- 一个打开的文件再内核中使用三种数据结构表示
- 文件描述符
- 文件描述符标志
- 文件表项指针
- 文件表项
- 文件状态标志
- 读、写、追加、同步和非阻塞等状态标志
- 当前文件偏移量
- i 节点表项指针
- 引用计数器
- 文件状态标志
- i 节点
- 文件类型和对该文件的操作函数指针
- 当前文件长度
- 文件所有者
- 文件所在的设备、文件访问权限
- 指向文件数据在磁盘上所在位置的指针等
- 文件描述符

4.3 原子操作
4.3.1 介绍
主要是open 函数中的文件追加和文件创建
- 文件追加
- 打开文件时,使用 O_APPEND 标志,进程对到文件偏移量调整和数据追加成为原子操作
- 内核每次对文件写之前,都将进程的当前偏移量设置为该文件的尾端。这样不再需要 lseek 来调整偏移量
- 文件创建
- 对 open 函数的 O_CREAT 和 O_EXCL 的同时使用,而该文件存在,open 将失败,否则创建该文件,并且使得文件是否存在的判定和创建过程成为原子操作。
例子:两个进程对同一文件进行追加,没有使用 append 的时候
file_append.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> int main(int argc, char *argv[])
{
if(argc < ) {
fprintf(stderr, "usage: %s content destfile\n", argv[]);
exit();
} int fd;
int ret;
size_t size; fd = open(argv[], O_WRONLY);
if(fd < ){
perror("open error");
exit();
} //定位到文件尾部
ret = lseek(fd, 0L, SEEK_END);
if(ret == -) {
perror("lseek error");
close(fd);
exit();
} sleep(); //睡眠 10s //往文件中追加内容
size = strlen(argv[]) * sizeof(char);
if(write(fd, argv[], size) != size) {
perror("write error");
close(fd);
exit();
} return ;
}
编译:gcc -o bin/file_append src/file_append.c
创建一个 append.txt 文件,然后开启两个终端运行此程序
第一个终端:
第二各终端:
第二个终端在第一个终端之后运行,运行完之后,查看 append.txt 的内容:

现象上说明,第二个终端的写入将第一个终端的写入给覆盖掉了。
第一个进程运行的时候,文件表项中的当前偏移量来源于 i 节点的文件长度(即调用 lseek 的时候),第二个进程运行的时候也是用 lseek 来获取偏移量,但是 i 节点中的文件长度没有增加,所以文件表项中的 当前偏移量 依然未变,因此第二个进程追加的内容覆盖掉了第一个进程中的内容。
要想不覆盖,则要使用原子操作。将 open 和 注释掉 lseek 的代码做修改:
//fd = open(argv[2], O_WRONLY);
fd = open(argv[], O_WRONLY | O_APPEND);
删除 appent.txt 中的内容,然后再次在两个终端中运行两个程序:

加了 O_APPEND 后,write 函数做了几件事情,此时整个 write 成为一个原子操作,只有当第一个进程的 write 执行完后,第二个进程的 write 才后执行:
- 从 i 节点中读取文件长度作为当前偏移量
- 往文件中写入数据
- 修改 i 节点中文件操作
四、文件IO——内核数据结构和原子操作的更多相关文章
- 第3章 文件I/O(3)_内核数据结构、原子操作
3. 文件I/O的内核数据结构 (1) 内核数据结构表 数据结构 主要成员 文件描述符表 ①文件描述符标志 ②文件表项指针 文件表项 ①文件状态标志(读.写.追加.同步和非阻塞等状态标志) ②当前文件 ...
- Unix系统编程()深入探究文件IO概述
open调用将引入原子atomicity操作的概念. 将某一系统调用所要完成的各个动作作为不可中断的操作,一次性加以执行. 原子操作是许多系统调用得以正确执行的必要条件. 还介绍一个系统调用fcntl ...
- 文件IO
在unix世界中视一切为文件,无论最基本的文本文件还是网络设备或是u盘,在内核看来它们的本质都是一样的.大多数文件IO操作只需要用到5个函数:open . read . write . lseek 以 ...
- UNIX高级环境编程(14)文件IO - O_DIRECT和O_SYNC详解 < 海棠花溪 >
春天来了,除了工作学习,大家也要注意锻炼身体,多出去运动运动. 上周末在元大都遗址公园海棠花溪拍的海棠花. 进入正题. O_DIRECT和O_SYNC是系统调用open的flag参数.通过指定o ...
- linux中文件内核数据结构
3.文件io 3.1 文件内核数据结构 3.2 复制文件描述符的内核数据结构 3.3 对指定的描述符打印文件标志 #include "apue.h" #include <fc ...
- 《UNIX环境高级编程》笔记——3.文件IO
一.引言 说明几个I/O函数:open.read.write.lseek和close,这些函数都是不带缓冲(不带缓冲,只调用内核的一个系统调用),这些函数不输入ISO C,是POSIX的一部分: 多进 ...
- linux中文件IO
一. linux常用文件IO接口 1.1. 文件描述符 1.1.1. 文件描述符的本质是一个数字,这个数字本质上是进程表中文件描述符表的一个表项,进程通过文件描述符作为index去索引查表得到文件表指 ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- linux内核数据结构学习总结
目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...
随机推荐
- 51nod 1081 子段求和(线段树 | 树状数组 | 前缀和)
题目链接:子段求和 题意:n个数字序列,m次询问,每次询问从第p个开始L长度序列的子段和为多少. 题解:线段树区间求和 | 树状数组区间求和 线段树: #include <cstdio> ...
- our happy ending(状压dp)
题意:给定一个n,k,l. 问有多少长度为n的序列满足选出一些数使得他们相加为k,数列中每个数都在1-l以内. Solution 正解还是很妙的. 状压dp,设dp[i][j]表示长度为i的序列,能表 ...
- 2019 校内赛 RPG的天赋分支(贪心)
Problem Description 很多游戏都有天赋树的概念,天赋树的不同分支具有不同的属性加成,那么合理选择分支就非常重要了.Luke最近沉迷一款RPG游戏,它的天赋树机制如下:角色具有n个可选 ...
- css预编译语言sass——mixin的使用
以根据不同屏幕吃寸动态应用背景图片为例 新建一个mixin如下: @mixin bg_img($path, $ext){ @media screen and (max-device-width: 76 ...
- 阿里云 docker连接总报超时 registry.cn-hangzhou.aliyuncs.com (Client.Timeout exceeded while awaiting headers
Error response from daemon: Get https://registry.cn-hangzhou.aliyuncs.com/v2/: net/http: request can ...
- [bzoj1563][诗人小g]
bzoj1563 思路 首先考虑\(n^2\)的暴力dp,用sum[i]表示前i句话的长度总和.f[i]表示前i句话最小的不协调度之和.转移的时候考虑枚举前面的每个点,找到转移的最优秀的那个点. 然后 ...
- Flask block继承和include包含
继承(Block)的本质是代码替换,继承我认为就是把完整的html文件继承到一个不完整的html文件里. 被继承html文件: <!DOCTYPE html> <html lang= ...
- jquery基本语法(一)
https://www.cnblogs.com/haiyan123/p/7657151.html 一.jQuery基础1.为什么要用jquery? 写起来简单,省事,开发效率高,兼容性好2.什么 ...
- vue学习(3)
回顾昨天内容 1.let和const 2.模板字符串 `` 插变量${变量名} 3.箭头函数 function(){} == ()=>{} 1.this的指向问题 2.arguments不能使用 ...
- 关于用户输入恶意js
有些黑客经常闲得蛋疼的那别人的网站测试,利用一些输入的漏洞提交js代码,搞恶作剧. 对于freemarker视图的web应用,可以参考以下方法: http://yshjava.iteye.com/bl ...