linux常用文件I/O操作之文件共享的实现方式



 1、文件共享的三种实现方式

 1、什么是文件共享:   

(1)文件共享就是同一个文件(同一个文件指的是同一个inode,同一个pathname)被多个独立的读写体(几乎可以理解为多个文件描述符)去同时(一个打开尚未关闭的同时另一个去操作)操作。

(2)文件共享的意义有很多:譬如我们可以通过文件共享来实现多线程同时操作同一个大文件,以减少文件读写时间,提升效率。

    2、文件共享的核心就是怎么弄出来多个文件描述符指向同一个文件。

    3、常见的三种文件共享情况:

1、是同一个进程中多次使用open函数打开同一个文件。

2、不同进程中分别使用open函数打开同一个文件(因为此时两个fd不在同意进程中,所以两个fd可能相同,也可能不同)。

3、linux提供的dup和dup2两个API来让进程赋值文件描述符。

 4、我们分析文件共享的核心关注点在于:分别写、读还是连续读写

补充:

再论文件描述符:

1、文件描述符的本质是一个数字,这个数字本质上是进程表中文件描述符的一个表项,进程通过文件描述符作为index去索引查表得到文件表指针,再间接访问得到这个文件对应的文件表。

2、文件描述符这个数字是open系统调用内部由操作系统自动分配的,操作系统分配这个fd也不是随机分配的,也会按照一定的规律。

3、操作系统规定,fd从0开始一次增加,fd也是有最大限制的,在linux的早期版本中fd最大只有20.linux中文件描述符表是一个数组(而不是链表),所以这个文件描述符表其实就是一个数组,fd是index,文件表指针是value

4、当我们open时,内核会从文件描述符表中挑选一个最小的未被使用的数字给我们返回。

文件描述符的复制:

5、fd中0、1、2已经默认被系统占用了,当我们运行一个程序得到一个进程时,内部就默认已经打开了3个文件,这三个文件对应的fd就是0、1、2。这三个文件分别叫stdin、stdout、stderr。也就是标准输入、标准输出、标准错误。因此用户进程得到的最小的fd就是3了。

6、标准输入一般对应的是键盘(可以理解为:0这个fd对应的是键盘的设备文件),标准输出一般是LCD显示器(可以理解为:1对应LCD的设备文件)

7、printf函数其实就是默认输出到标准输出stdout上了。stdio中还有一个函数叫fpirntf,这个函数就可以指定输出到哪个文件描述符中。

2、如何实现文件共享

1、同一个进程中多次使用open函数打开同一个文件。同时打开同一个文件不难理解,关键在于打开同一个文件后,我们读取写入文件时,是分别写呢还是接续写,简单理解就是,覆盖着写呢?还是一个写完了,文件指针自动挪到后边分开写?我们不用去猜,记别人的理论,我们直接自己用代码测试,只要代码正确的情况测试的结果就是理论。下来我们来看测试代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>

typedef int file_t;  
#define MAXLENG 1024

int main(int argc,char *argv[])
{
   file_t  fd1 = -1, fd2 = -1;
  
   fd1 = open("./1.txt",O_RDWR | O_TRUNC | O_CREAT,0644);

   if(fd1 < 0)
   {
	   perror("fd1 :open file failed :");
	   _exit(-1);
   }

   fprintf(stdout,"fd1 = %d\n",fd1);
   
   
//这里为了区别更明显,	fd2的open以及判断完全可以放在fd1的判断中去
   fd2 = open("./1.txt",O_RDWR | O_TRUNC | O_CREAT,0644);

   if(fd2 < 0)
   {
	   perror("fd2:open file fialed :");
	   _exit(-1);
    }

   fprintf(stdout,"fd2 = %d\n",fd2);

   while(1)
   {
	  
	   write(fd1,"aaaa",4);
	   sleep(1);
	   write(fd2,"bbbb",4);
   }
   
   return 0;

}

这段代码运行完成以后,我们来看结果

[[email protected]_k filetest]# cat 1.txt 
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaa[[email protected]_k filetest]#

这样我们可以很容易看到,我们虽然是用两个文件指针分别写,但是fd1只有在最后一次写进去,对吧?这时我们看到的;但是这为什么会这样呢?这里我们分析一下:其实fd1进行了写入操作,只是我们fd1和fd2两个文件指针是不同的文件指针,当fd1写入以后,文件指针往后移动,但是fd2并没有移动,当fd2进行写入时就会覆盖掉fd1写入的内容,并且这里与你两次打开文件的属性有关,这里使用

O_RDWR | O_TRUNC | O_CREAT三个属性打开,我们也可以自己测试其他属性打开的结果。虽然不同属性打开的结果可能造成的结果不同,但是我们这里是可以确定的,一个文件指针移动后并不会造成另外一个文件指针移动。

2、第二种方法用不同进程中分别使用open函数打开同一个文件(因为此时两个fd不在同意进程中,所以两个fd可能相同,也可能不同)。这里还没有总结fork函数产生新的进程。所以先不总结,博主后边补充上去。

   3、使用linux提供的dup和dup2两个API来让进程赋值文件描述符。

  1、使用dup进行文件描述符复制

(1)dup系统调用对fd进行复制,会返回一个新的文件描述符(譬如原来的fd是3,返回的就是4)

(2)dup系统调用有一个特点,就是自己不能指定复制后得到的fd的数字是多少,而是由操作系统内部自动分配的,分配的原则遵守fd分配的原则。

(3)dup返回的fd和原来的oldfd都指向oldfd打开的那个动态文件,操作这两个fd实际操作的都是oldfd打开的那个文件。实际上构成了文件共享。

(4)dup返回的fd和原来的oldfd同时向一个文件写入时,结果是分别写还是接续写?

使用dup的缺陷分析

(1)dup并不能指定分配的新的文件描述符的数字,dup2系统调用修复了这个缺陷,所以平时项目中实际使用时根据具体情况来决定用dup还是dup2.

  2、使用dup2进行文件描述符复制

(1)dup2和dup的作用是一样的,都是复制一个新的文件描述符。但是dup2允许用户指定新的文件描述符的数字。

(2)使用方法看man手册函数原型即可。

测试使用dup和dup2共享文件操作:

    1、dup共享文件的实现

    

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<errno.h>

typedef int file_t;
#define MAXSIZE 1024

int main(int argc,char *argv[])
{
	file_t fd1 = -1, fd2 = -1;
	fd1 = open("./3.txt",O_RDWR | O_CREAT | O_TRUNC,0644);

	if(fd1 < 0)
	 {
		perror("open fiel error :");
		_exit(-1);
	}

	fprintf(stdout,"fd1 = %d\n",fd1);

	fd2 = dup(fd1);

	if(-1 == fd2)
	{
		perror("dup error:");
		_exit(-1);
 	}

	fprintf(stdout,"fd2 = %d\n",fd2);

	while(1)
	{
		write(fd1,"aaaa",4);
		sleep(1);
		write(fd2,"bbbb",4);

	}

	return 0;
}

我们继续来看结果:

[[email protected]_k filetest]# cat 3.txt 
aaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaa
aabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaabbbbaaaa
[[email protected]_k filetest]#

从结果我们这次可以发现a和b是交替出现的,这也符合预期,dup虽然是产生了两个文件描述符,但是共用同一个文件指针,当一个写入以后,文件指针已经移动到后边去,自然不会覆盖掉了。

   2、dup2共享文件交叉写入测试

    1、对于dup2和dup写入文件一样,区别在于dup2可以自己指定文件描述符,所以这里就不给出dup2写入文件的实例。

    2、交叉写入的时候,结果是接续写

3、fcntl函数

  1、fcntl函数是一个多功能文件管理的工具箱,可以接受2个参数+1个变参,第一个参数是fd表示哟啊操作那个文件,第二个参数是cmd表示要进行那个命令操作。变参是用来传递参数的,要配合cmd命令使用

    2、cmd的样子类似于F_XXX,不同的cmd具有不同的功能。学习时,没有必要把所有的cmd含义弄清楚,只需要把一个弄明白就行,其他的查man手册即可。

    3、常用fcntl的cmd  

1、F_DUPFD这个cmd的作用是复制文件描述符(作用类似于dup和dup2),这个命令的功能是从可用的fd数字列表中找一个比arg大或者和arg一样大的数字作为oldfd的一个复制的fd,和dup2有点像但是不同。dup2返回的就是我们指定的那个newfd否则就会出错,但是F_DUPFD命令返回的是>=arg的最小的那一个数字。

4、标准I/O库

  1、标准IO和文件IO有什么区别

1、最大的区别:标准I/O库是C库函数,而文件I/O是linux系统调用的API

2、C语言库函数是由API封装起来的,库函数内部也是通过调用API来完成操作的,但是库函数多了一层封装,所以比API更加好用。

3、库函数比API还有一个优势,API在不同的操作系统的接口是不一样的是不能通用的,但是C库函数在不同操作系统上几乎是一样的,所以C库函数具有可移植性而API不具有可移植性。

  2、常用标准IO函数介绍:

常见的标准IO库函数:fopen fclose fwrite fread ffulsh、fseek



以上文档,本人学习参考了不同老师的文档自己总结而来,代码都是本人亲自测试。关于文档那块有问题,请各位指正。

时间: 2024-10-27 11:33:14

linux常用文件I/O操作之文件共享的实现方式的相关文章

自定义的常用文件与目录操作函数库

自定义的常用文件与目录操作函数库,在win和linux平台做了跨平台的处理.(跨平台的处理可以作为参考比较.在win下目录的符号可以是\或者/,但是在linux下只能是/.) 下面给出的是源文件,实现接口函数的代码.每个接口函数都有很详细的功能说明. /* 判断文件或目录是否存在 * 在操作系统中,目录也是一个文件,如果要判断一个目录是否存在则应当使用DirectoryExists, * 要判断一个文件是否存在且是一个归档文件则应当使用IsArchive. * @如果文件或目录存在则返回true

linux下文件的读写操作(openreadwrite)

linux下文件的读写操作(openreadwrite) 转 http://www.2cto.com/os/201403/285837.html open(打开文件) 相关函数 read,write,fcntl,close,link,stat,umask,unlink,fopen 表头文件 #include<sys/types.h>#include<sys/stat.h>#include<fcntl.h> 定义函数 int open( const char * path

linux中文件I/O操作(系统I/O)

我们都知道linux下所有设备都是以文件存在的,所以当我们需要用到这些设备的时候,首先就需要打开它们,下面我们来详细了解一下文件I/O操作. 用到的文件I/O有以下几个操作:打开文件.读文件.写文件.关闭文件等,对应用到的函数有:open.read.write.close.lseek(文件指针偏移) 文件描述符:对于内核而言,所有打开的文件都通过文件按描述符引用.文件描述符是一个非负整数.                      当打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描

【linux之文件查看,操作】

一.shell如何处理命令 1.shell会根据在命令中出现的空格字符,将命令划分为多个部分 2.判断第一个字段是内部命令还是外部命令 内部命令:内置于shell的命令(shell builtin) 外部命令:通过安装其他应用程序或服务而安装来的命令 路径:为了查找或定位某个文件所必需经过的目录的层次结构 相对路径:从工作目录开始查找的路径 . 当前的工作目录 .. 当前的工作目录的父目录 根的父目录还是根 绝对路径:从根(/)开始查找的路径 变量:内存空间 变量值:存放在内存空间中的数据 空变

linux常用文件操作命令

目录 本文列出了linux常用的文件操作命令,如 解压缩文件 查看文件内容 编辑文件内容 创建文件/删除文件 创建目录/删除目录 复制/移动文件(夹) 查看文件/目录当前绝对路径 查看文件(夹)大小 查看/修改文件(夹)权限 修改文件(夹)名称 查看目录下文件夹/文件 正文 解压缩文件 tar –xvf file.tar //解压 tar包 tar -xzvf file.tar.gz //解压tar.gz tar -xjvf file.tar.bz2 //解压 tar.bz2 tar –xZvf

Linux下文件权限相关操作

一 权限掩码umask umask是chmod配套的,总共为4位(gid/uid,属主,组权,其它用户的权限),不过通常用到的是后3个,例如你用chmod 755 file(此时这文件的权限是属主读(4)+写(2)+执行(1),同组的和其它用户有读写权限) 二 umask的作用 默认情况下的umask值是022(可以用umask命令查看),此时你建立的文件默认权限是644(6-0,6-2,6-2),建立的目录的默认 权限是755(7-0,7-2,7-2),可以用ls -l验证一下哦 现在应该知道

linux 常用文件命令记录

服务开启命令 service  服务  start/stop/stauts 查看ip ifconfig 清屏 clear 显示当前所在位置 pwd 切换目录 cd 查看所有文件(包括隐藏) ls -a 创建目录 mkdir 创建多级目录(递归创建) mkdir  -p 123/abc 删除目录 (空) rmdir 删除目录 rm  -r 删除目录 -f 强制 rm -rf 强制删除目录 删除文件 rm 复制命令 cp 复制目录 cp -r 复制文件属性(内容 属性 时间 ) cp -a 显示时间

Linux的文件、目录操作

cd   切换目录 cd  /bin  切换到bin目录(指定目录),cd即change dir cd  ..     切换过到当前目录的上一级目录,可以用..,也可以用../ cd  /    切换到系统根目录 cd  ~   切换到当前用户的根目录,比如我的用户名是chy => /home/chy cd  -    切换到上一个目录,是上一个,不是上一级,类似于历史记录中的上一个,很多终端的-都表示上一个 Linux只有一个盘符,只有一个根目录/,没有切换盘符的说法. 新建.删除目录 mkd

linux下文件的简单操作(创建、查看、链接、打包压缩、查找)

对文件的基本操作有很多零散的命令,做一个小总结,基本分为 创建.查看.链接.打包压缩.查找 创建: mkdir:创建目录 mkdir [-p 建立多层目录] [-m 同时设置权限] mkdir -p /test/test mkdir -m 774 test touch:创建文件/修改文件时间参数 touch [-a 修改访问时间到当前时间] [-c 修改权限和内容修改时间到当前时间] [-m 修改具体内容修改时间到当前时间] [-t 修改成指定的时间] filename access time: