Linux环境编程之文件I/O(四):文件I/O的数据结构

(一)

Linux系统支持不同进程间共享打开的文件。内核使用三种数据结构表示打开的文件:进程表项、文件表项、v节点表。

1、进程表项:每个进程在进程表中都有一个记录项,记录项中年包含有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:

a、文件描述符标志

b、指向一个文件表项的指针

2、内核为所有打开文件维持一张文件表。每个文件表项包含:

a、文件状态标志,如读写、添加、同步和非阻塞等。

b、当前文件偏移量

c、指向该文件v节点表项的指针

3、每个打开的文件都有一个v节点结构。v节点包含了文件类型和对此文件进行各种操作的函数的指针。对于大多数文件,v节点还包含了该文件的i节点。

如果两个独立进程各自打开了同一个文件,假定第一个进程在文件描述符3上打开该文件,而另一个进程则在文件描述符4上打开该文件。打开该文件的每个进程都得到一个文件表项,但对一个给定的文件只有一个v节点表项。每个进程都有自己的文件表项的理由是:这样使得每个进程都有它自己的对该文件的当前偏移量。如下图:

注意三个概念:文件描述符标志、文件状态标志、文件描述符。

文件描述符标志(close_on_exec),它仅仅是一个标志,当fork了一个子进程,然后在子进程中调用了exec函数时就用到了该标志,它的含义就是,执行exec钱是否要关闭这个文件描述符,它的作用域只用于一个进程的一个描述符。而文件状态标志是在系统文件表中,读写可执行等这些标志,适用于指向该给定文件表项的任何进程中的所有描述符。

(二)

既然文件可以共享,那不同进程间共享同一个文件时,就可能出现并发竞态等问题。针对不同的竞态问题,我们有不同的策略。

1、若两个进程同时对一个文件进行写操作,则可能使其中一个的写数据被另外一个的写数据覆盖,针对这种情况,采取的办法是在open打开文件时设置O_APPEND标志。

2、Linux还允许原子性地定位搜索(seek)和执行I/O。其中pread和pwrite就是这种的函数。

#include <unistd.h>

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

调用pread相当于顺序调用lseek和read,但pread又与这种顺序调用有下列区别:

a、调用pread时,无法中断其定位和读操作。

b、不更改文件指针

调用pwrite相当于顺序调用lseek和write,但也与他们有类似的区别。

(三)

可以使用dup和dup2函数复制一个现存的文件描述符

#include <unistd.h>

int dup(int oldfd);   // 返回的新文件描述符一定是当前可用文件描述符中的最小数值。

int dup2(int oldfd, int newfd);  // 可以用newfd参数指定新描述符的数值,如果newfd已经打开,则现先将其关闭。如果newfd等于oldfd,则dup2返回newfd,而不关闭它。

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int
main(int argc, char *argv[])
{
	int fd;
	int nfd;
	char buf[] = "fjakdjl";

	fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
	if(fd < 0)
			printf("open error\n");
	printf("fd = %d.\n", fd);
	//dup2
	nfd = dup2(fd,4);
	if(nfd < 0){
		printf("error!\n");
	}
	printf("nfd = %d.\n", nfd);
	return 0;
}

编译测试:

编译
gcc dup.c
执行
./a.out
显示结果
fd = 3.
nfd = 4.

(四)

为保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性。Linux系统提供了sync、fsync、fdatasync三个函数。

#include <unistd.h>

int fsync(int fd);  //只对文件描述符fd指定的单一文件起作用,并且等待写磁盘操作结束,然后返回

int fdatasync(int fd);      // 类似于fsync,但它只影响文件的数据部分,出数据部分外,fsync还会同步更新文件的属性。

void sync(void);             // 只是对所有修改过的快缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作。

Linux环境编程之文件I/O(四):文件I/O的数据结构,布布扣,bubuko.com

时间: 2024-10-06 00:07:55

Linux环境编程之文件I/O(四):文件I/O的数据结构的相关文章

Linux环境编程之文件I/O(六):文件属性

引言: 在Linux中使用ls -l filename命令查看filename的属性时,会列出文件的9种属性,例如:ls -l /etc/fstab -rw-r--r-- 1 root root 1102 2013-10-12 02:33 /etc/fstab 从左到右分别是类型与权限.文件个数.该文件或目录的拥有者.所属的组.文件大小.创建时间.文件名 以上这些文件属性的信息,都存放在一个stat的结构体中.下面就来分析一下这个结构体. 要想查看一个文件的stat结构体,可以通过stat类函数

Linux环境编程之文件I/O(七):目录文件及操作

什么是数据结构? 数据结构是相互之间存在一种或多种特定关系的数据元素的集合. 还有一些概念(数据.数据元素.数据项.数据对象.数据类型...) 传统上,我们把数据结构分为逻辑结构和物理结构. 逻辑结构:是指数据对象中数据元素之间的相互关系,也是我们今后最需要关注和讨论的问题. 物理结构:是指数据的逻辑结构在计算机中的存储形式. 逻辑结构分为以下四种: 1.集合:集合结构中的数据元素除了同属于一个集合外,之间没有任何关系. 2.线性结构:元素之间一对一. 3.树形结构:一对多. 4.图形结构:多对

Linux环境编程之文件I/O(二):文件的打开与关闭

(一) Linux系统中,要对一个文件进行任何操作,必须首先获得它的文件描述符.而获得文件描述符的方式就是利用open/creat函数打开/创建该文件,open/creat函数返回文件描述符. #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, in

Linux环境编程之文件I/O(三):文件的读写

(一) 当我们打开了一个文件后,一般对文件的操作就是读写.读写函数分别是read.write. #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); 参数: fd:利用open.creat得到的文件描述符. buf:buf是void *类型,用于表示通用指针,此处指所读取到的数据的内存缓冲. count:需要读取的数据量. 返回值:成功执行时,返回所读取的数据的字节数,一般等于或小于所请求读取的数据字节数.若已到文

Linux环境编程之同步(四):Posix信号量

信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语.有三种类型:Posix有名信号量,使用Posix IPC名字标识:Posix基于内存的信号量,存放在共享内存区中:System V信号量,在内核中维护.这三种信号量都可用于进程间或线程间的同步. 图1 由两个进程使用的一个二值信号量 图2 由两个进程使用的一个Posix有名二值信号量 图3 由一个进程内的两个线程共享的基于内存的信号量 一个进程可以在某个信号量上执行的三种操作: 1.创建一个信号量,这要求调用者指定初始值,对

Linux环境编程之进程(四):创建新进程、执行程序和进程终止

引言: 对于每个进程,都有一个非负整数表示的唯一进程ID.虽然进程的ID是唯一的,但却是可重用的.系统中有一些专用的进程.如ID为0的进程通常是调度进程,也成交换进程或系统进程(它是内核进程).进程ID为1通常是init进程,它是一个普通的用户进程.一些与进程ID有关的函数: #include <unistd.h> pid_t getpid(void);   //返回值:调用进程的进程ID pit_t getppid(void); //返回值:调用进程的父进程ID uid_t getuid(v

Linux环境编程之文件I/O(八):文件链接

引言: 执行如下命令时, ls /usr/local/lib/libfreetype.so -l 显示内容: lrwxrwxrwx 1 root root 20 2014-04-06 22:57 /usr/local/lib/libfreetype.so -> libfreetype.so.6.9.0 表明这是一个链接文件,通过链接可以实现对一个文件从不同路径对它进行引用.对于文件的链接有硬链接和软连接(即符号链接)之分.shell中的ln命令可以创建一个文件的硬链接,加上-s选项可以创建一个文

Linux环境编程之文件I/O(五):fcntl函数

引言: 对于一个普通的文件,我们可以想到的对它的操作有,读取文件的内容.写数据到文件中,这些都是前面提到的read.write函数的作用.除此之外,还可以获取文件的其他性质,并对这些性质进行修改,比如文件的描述符.文件描述符标记.文件状态标志等等.这些对文件性质的修改就由fcntl函数完成. 函数介绍: #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 参数: fd:

Linux环境编程之文件I/O(一):文件描述符

(一) 首先,对于内核来讲,它是利用"文件描述符"来访问文件的.文件描述符一般是一个非负的整数.当我们用open打开已有的文件或者用creat创建新的文件时,都会返回一个文件描述符.有了文件描述符之后,我们就可以利用该文件描述进行文件的读写,即read.write系统调用都需要文件描述符fd(file descriptor)作为其参数.从以上描述可以看出,当我们想要用read.write等系统调用对文件进行读写等操作之前,必须用open或creat系统调用得到文件的描述符. 一般Uni