初级文件IO——若干种文件共享操作 如何影响 文件文件描述符表
同一进程共享操作相同的文件
在同一个进程中多次open打开同一文件时,文件描述符可能会相同吗?
答:不可能。在同一进程里面,一旦某个文件描述符被用了,在close释放之前,别人不可能使用,所以指向同一文件的描述符不可能相同。
代码演示
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #define FILE_NAME "./file.txt" void print_error(char * str)
{
perror(str);
exit(-);
} int main(void)
{
int fd1 = ;
int fd2 = ; fd1 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(- == fd1) print_error("1 open fail"); fd2 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(fd2 == -) print_error("2 open fail"); printf("fd1 = %d, fd2 = %d\n", fd1, fd2); while()
{
write(fd2, "world\n", );
sleep();
write(fd1, "hello\n", );
} return ;
}
file.txt文件内容会出现覆盖写情况,看看共享操作时的文件描述符表长啥样

由图知道,正是由于不同的文件描述符,各自对应一个独立的文件表,在文件表中有属于自己的“文件位移量”,开始时都是0。各自从0开始写,每写一个字节向后移动一个字节,他们写的位置是重叠的,因此肯定会相互的覆盖。
问题如何解决
指定O_APPEND即可解决。必须每个open都要指定,有一个不指定就会覆盖,就先过马路一样,都要准守交通规则才能安全,开车的和行人,只要有一个不准守都会出事。
为什么使用O_APPEND可以解决?
文件长度信息是大家共享的,当文件被写入数据后,文件长度就会被更新,都指定O_APPEND后,使用不同的文件描述符写数据时,都会使用文件长度更新自己的文件位移量,保证每次都是在文件的最末尾写数据,就不会出现相互覆盖的情况。
多个进程之间,共享操作相同文件
代码演示
shareOp_file1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #define FILE_NAME "./file.txt" void print_error(char * str)
{
perror(str);
exit(-);
} int main(void)
{
int fd1 = ; fd1 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(- == fd1) print_error("1 open fail"); printf("fd1 = %d\n", fd1); while()
{
write(fd1, "hello\n", );
sleep();
} return ;
}
shareOp_file2.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #define FILE_NAME "./file.txt" void print_error(char * str)
{
perror(str);
exit(-);
} int main(void)
{
int fd1 = ; fd1 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(- == fd1) print_error("1 open fail"); printf("fd1 = %d\n", fd1); while()
{
write(fd1, "world\n", );
sleep();
} return ;
}
不同进程打开同一文件时,各自使用的文件描述符值可能相等,比如我们例子中的1和2进程,它们open后的描述符就相等。之所以相同,是因为不同的进程有自己独立的文件描述符池,都是0~1023的范围,各自分配自己的,有可能分派到相等值的文件描述符。
进程表 和 文件描述符表

覆盖的原因
和单个进程打开多个文件类似,这种情况也会覆盖写。其原因是因为因为各自有独立的文件位移量。
解决办法
同样的,指定O_APPEND标志,写操作时,使用文件长度去更新文件位移量,保证各自操作时,都在文件的尾部操作,就不会出现相互覆盖的情况。
父子进程共享操作文件
独立打开文件
这种情况即多个进程独立打开同一文件实现共享操作,只不过这里面进程之间是父子关系
代码演示
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int main(void)
{
pid_t ret = ;
int fd = ; ret = fork();
if(ret > )
{
fd = open("./file.txt", O_RDWR|O_CREAT|O_APPEND, ); write(fd, "hello\n", );
}
else if(ret == )
{
fd = open("./file.txt", O_RDWR|O_CREAT|O_APPEND, ); write(fd, "world\n", );
} return ;
}
文件表结构

独立打开同一文件时,父子进程各自的文件描述符,指向的是不同的文件表。因为拥有不同的文件表,所以他们拥有各自独立的文件读写位置,会出现相互覆盖情况,如果不想相互覆盖,需要加O_APPEND标志。
fork之前打开文件
代码演示
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int main(void)
{
pid_t ret = ;
int fd = ; fd = open("./file.txt", O_RDWR|O_CREAT, );
ret = fork();
if(ret > )
{
write(fd, "hello\n", );
printf("p, uid = %d, gid = %d\n", getuid(), getgid());
}
else if(ret == )
{
write(fd, "world\n", );
printf("c, uid = %d, gid = %d\n", getuid(), getgid());
} return ;
}
文件表结构

子进程会继承父进程已经打开的文件描述符,如果父进程的3描述符指向了某个文件,子进程所继承的文件描述符3也会指向这个文件。像这种继承的情况,父子进程这两个相同的“文件描述符”指向的是相同的“文件表”。由于共享的是相同的文件表,所以拥有共同的文件读写位置,不会出现覆盖的情况。
子进程的0 1 2这三个打开的文件描述符,其实也是从父进程那里继承过来的,并不是子进程自己去打开的,同样的父进程的0 1 2又是从它的父进程那里继承过来的,最根溯源的话,都是从最原始的进程哪里继承过来的,参考:进程控制——三大主要进程 ,最原始的进程是init进程。
init进程会去打开标准输入,标注输出、标准出错输出这三个文件,然后0 1 2分别指向打开的文件,之后所有进程的0 1 2,实际上都是从最开始的init进程那里继承而来的。

初级文件IO——若干种文件共享操作 如何影响 文件文件描述符表的更多相关文章
- 文件的三种打开方式及with管理文件上下文
文件的三种打开方式及with管理文件上下文 一.文件的三种打开方式 1.1 只读 f = open(r'D:\pycharm\yjy\上海python学习\456.txt','r',encoding= ...
- LInux文件基础知识和文件目录操作(二)文件I/O操作
1.文件I/O操作分为两部分来讲解: 第一部分是非缓冲文件操作,这种操作适合于比较小规模文件的读写和对实时性要求很高的设备的数据通信,这类操作是系统调用提供的: 第二部分是缓冲文件操作,所面向的则是大 ...
- java读取txt文件,对字符串进行操作后导出txt文件
嘿嘿,代码略为简单,不再多做解释,直接上码! package org.lq.com.util; import java.io.File; import java.io.InputStreamReade ...
- Lua的文件IO操作
Lua 标准库 - 输入输出处理(input and output facilities) 转载于:http://blog.csdn.net/duanxuyun 文本Tag: Lua [IT168 技 ...
- 【UNIX环境高级编程】文件 IO 操作 一 ( open | close | creat | lseek | write | read )
博客地址 : http://blog.csdn.net/shulianghan/article/details/46980271 一. 文件打开关闭操作相关函数介绍 1. open 函数 (1) op ...
- 《嵌入式linux应用程序开发标准教程》笔记——6.文件IO编程
前段时间看APUE,确实比较详细,不过过于详细了,当成工具书倒是比较合适,还是读一读这种培训机构的书籍,进度会比较快,遇到问题时再回去翻翻APUE,这样的效率可能更高一些. <嵌入式linux应 ...
- 三、文件IO——系统调用
3.1 文件描述符 文件IO 系统调用是不带缓存的,文件 I/O 系统调用不是 ANSI C 的组成部分,是 POSIX 的组成部分. 系统调用与C库: C库函数的IO 的底层还是调用系统调用 I/O ...
- 文件IO和标准IO的区别【转】
一.先来了解下什么是文件I/O和标准I/O: 文件I/O:文件I/O称之为不带缓存的IO(unbuffered I/O).不带缓存指的是每个read,write都调用内核中的一个系统调用.也就是一般所 ...
- 标准IO与文件IO 的区别【转】
本文转载自:http://blog.sina.com.cn/s/blog_63f31f3401013jrn.html 先来了解下什么是标准IO以及文件IO. 标准IO:标准I/O是ANSI C建立的一 ...
随机推荐
- django项目添加路由----返回给客户端内容-----windows中的python
django项目添加路由 url函数的第一个参数是匹配url路径的正则表达式,第2个参数是路由函数 第一个正则表达式是r'^$',其中r表示正则表达式字符串不对转义符进行转义.“^”表示匹配URL路径 ...
- laravel5.5的定时任务详解(demo)
原文地址:https://blog.csdn.net/LJFPHP/article/details/80417552
- Python数据结构与语法
字典:Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串.数字.元组.字典等其他容器模型:值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组:遍历字典时遍历的是键:访问v ...
- 齐治堡垒机前台远程命令执行漏洞(CNVD-2019-20835)分析
一.基本信息 漏洞公告:https://www.cnvd.org.cn/flaw/show/1632201 补丁信息:该漏洞的修复补丁已发布,如果客户尚未修复该补丁,可联系齐治科技的技术支持人员获得具 ...
- hi cnblogs
hi cnblogs 前言: 作为一个工作好些年的it男,还没正经写过技术博客,真是太羞愧了... 正文: 先扯点儿虚的,无论从事什么行业,最重要的都是自我认知和自我定位.至今,我也有工作了小五年了, ...
- 修改Ubuntu屏幕的分辨率
最近重新装了一下环境,用vnc连接服务器,发现分辨率过低,于是查了一下如何修改分辨率,将其调高. 编辑/etc/default/grub 搜索"#GRUB_GFXMODE=640x4 ...
- 什么是Java内部类?
如果大家想了解更多的知识和技术,大家可以 搜索我的公众号:理想二旬不止 (尾部有二维码)或者访问我的 个人技术博客 www.ideal-20.cn 这样阅读起来会更加舒适一些 非常高兴与大家交流,学习 ...
- js穿梭框;将两个table中的数据选中移动
将table中选中的数据移动到右边: 点击一行中的任意一个位置,使其选中: 注:attr()和prop()都是jquery的方法: .attr() : 获取匹配的元素集合中的第一个元素的属性的值 或 ...
- Guava 工具类之Strings 的使用
public class StringTest { public static void main(String[] args) { //判断是null还是空字符串 boolean b1 = Stri ...
- flannel vxlan工作基本原理及常见排障方法
写在前面 最近用kubeadm鼓捣了几个cluster集群测试用,网络用的flannel.因为这些机器都不是纯净的环境(以前部署过其他的k8s或者有一些特别的设置),所以部署起来遇到了很多问题.看了下 ...