UNIX环境编程学习笔记(4)——文件I/O之dup复制文件描述符

lienhua34
2014-08-23

UNIX 提供了两个函数 dup 和 dup2 用于复制一个现存的文件描述符。

#include <unistd.h>

int dup(int filedes);

int dup2(int filedes, int filedes2);

返回值:若成功则返回新的文件描述符,如出错则返回-1.

由 dup 函数返回的文件描述符一定是当前可用文件描述符中的最小描述符。用 dup2 函数则可以通过参数 filedes2 指定目标文件描述符。如果filedes2 已经打开,则先将其关闭。如果 filedes 等于 filedes2,则 dup2 函数返回 filedes2,而不关闭它。

下面程序使用 open 打开文件 foo.txt,先使用 lseek 获取该文件描述符的当前偏移量。然后,调用 dup 该文件描述符,并调用 lseek 将新文件描述符的当前偏移量设置为距离文件开始处的 10 字节处。最后,用 lseek 获取并打印这两个文件描述符的当前偏移量。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP
int
main(void)
{
    int fd, fddup;
    off_t fdoff, fddupoff;
    if ((fd = open("foo.txt", O_WRONLY | O_CREAT | O_TRUNC, FILE_MODE)) < 0) {
        printf("open error");
        exit(-1);
    }
    if ((fdoff = lseek(fd, 0L, SEEK_CUR)) == -1) {
        printf("lseek error");
        exit(-1);
    }
    printf("fd offset(before dup): %d\n", fdoff);
    if ((fddup = dup(fd)) == -1) {
        printf("dup error");
        exit(-1);
    }
    if ((fddupoff = lseek(fddup, 10L, SEEK_SET)) == -1) {
        printf("lseek error");
        exit(-1);
    }
    printf("fddup offset(after dup): %d\n", fddupoff);
    if ((fdoff = lseek(fd, 0L, SEEK_CUR)) == -1) {
        printf("lseek error");
        exit(-1);
    }
    printf("fd offset(after dup): %d\n", fdoff);
    exit(0);
}

编译该程序生成 dupdemo,然后运行该 dupdemo 文件,

lienhua34:demo$ gcc -o dupdemo dup_demo.c
lienhua34:demo$ ./dupdemo
fd offset(before dup): 0
fddup offset(after dup): 10
fd offset(after dup): 10

从 dupdemo 运行结果可以看到,对 dup 得到的文件描述符设置了文件当前偏移量,同时影响到了原来的文件描述符的当前偏移量。这是因为,dup 函数得到的新文件描述符跟原文件描述符共享了同一个文件表项,其内核数据结构如图 1 所示。

图 1: dup 后的内核数据结构

另外,每个文件描述符都有它自己的一套文件描述符标志。dup 得到的新文件描述符的执行时关闭(close-on-exec)标志总是有 dup 函数清除。

时间: 2024-12-28 16:42:31

UNIX环境编程学习笔记(4)——文件I/O之dup复制文件描述符的相关文章

UNIX环境编程学习笔记(13)——文件I/O之标准I/O流

lienhua342014-09-29 1 标准 I/O 流 之前学习的都是不带缓冲的 I/O 操作函数,直接针对文件描述符的,每调用一次函数可能都会触发一次系统调用,单次调用可能比较快捷.但是,对于需要频繁进行 I/O 操作的程序,频繁触发系统调用产生的消耗太大. 标准 I/O 库提供了带缓冲的 I/O 操作函数,这些函数围绕着一种叫做流(stream)的东西进行.当使用标准 I/O 库打开或创建一个文件时,系统提供了一个流与这个文件相关联.通过流的读入和输出完成所需要的 I/O操作. 标准

UNIX环境编程学习笔记(6)——文件I/O之判断文件类型

lienhua342014-09-01 1 文件类型 我们平时最常接触的文件类型有普通文件(regular file)和目录(di-rectory file),但是 UNIX 系统提供了多种文件类型: (1) 普通文件(regular file) 这种文件包含了某种形式的数据,这些数据无论是文件还是二进制对于 UNIX 内核而言都是一样的.对普通文件内容的解释有处理该文件的应用程序进行. (2) 目录文件(directory file) 目录文件包含了其他文件的名字以及指向与这些文件有关信息的指

UNIX环境编程学习笔记(9)——文件I/O之文件访问权限的屏蔽和更改

lienhua342014-09-10 1 文件访问权限 在文件访问权限和进程访问控制中,我们已经讲述过文件访问权限位,为了方便,我们重新列在下面, 表 1: 文件的 9 个访问权限位  st_mode 屏蔽  意义  S_IRUSR  用户 -读  S_IWUSR  用户 -写  S_IXUSR  用户 -执行  S_IRGRP   组 -读  S_IWGRP  组 -写  S_IXGRP  组 -执行  S_IROTH  其他 -读  S_IWOTH  其他 -写  S_IXOTH  其他

UNIX环境编程学习笔记(7)——文件I/O之文件访问权限与进程访问控制

lienhua342014-09-02 1 文件的设置用户 ID位 和设置组 ID位 与进程相关联的 ID 如下表所示, 表 1: 与进程相关联的用户 ID 和组 ID 实际用户 ID 我们实际上是谁 实际组 ID 有效用户 ID 用于文件访问权限检查 有效组 ID 附加组 ID 保存的设置用户 ID 由 exec 函数保存 保存的设置组 ID 保存的设置用户 ID 和保存的设置组 ID 在执行一个程序时包含了有效用户 ID 和有效组 ID 的副本,这个后面我们学习到进程时在详细学习. 此处,我

UNIX环境编程学习笔记(3)——文件I/O之内核 I/O 数据结构

lienhua342014-08-27 内核使用三种数据结构表示打开的文件,分别是文件描述符表.文件表和 V 节点表. (1) 每个进程在进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,每个描述符占用一项.与每个文件描述符相关联的是: (a) 文件描述符标志. (b) 指向一个文件表项的指针. (2) 内核为所有打开文件维持一张文件表.每个文件表项包含: (a) 文件状态标志(读.写.添写.同步和非阻塞等). (b) 当前文件偏移量. (c) 指向该文件 V 节点表项的指针. (3)

UNIX环境编程学习笔记(12)——文件I/O之目录操作

lienhua342014-09-18 1 引言 在 UNIX 系统中,目录是一种特殊的文件类型.我们可以使用 open 函数来打开目录,获取文件描述符,然后调用 stat 函数来获取目录的属性信息,但是我们却不能够使用 read 函数来读取目录内容.例如,下面例子所示, #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <fcn

UNIX环境编程学习笔记(5)——文件I/O之fcntl函数访问已打开文件的性质

lienhua342014-08-29 fcntl 函数可以改变已打开的文件的性质. #include <fcntl.h> int fcntl(int filedes, int cmd, ... /* int arg */); fcntl 函数有 5 种功能: 1. 复制一个现有的描述符(cmd=F_DUPFD). 2. 获取/设置文件描述符标志(cmd=F_GETFD 或F_SETFD). 3. 获取/设置文件状态标志(cmd=F_GETFL 或F_SETFL). 4. 获取/设置异步 I/

UNIX环境编程学习笔记(1):——出错处理errno

lienhua342014 年 8 月 24 日 1. errno变量 文件 <errno.h> 中定义了符号 errno 以及可以赋予它的各种常量,这些常量都是以字符 E 开头.例如,若 errno 等于常量 EACCES,表示产生了权限问题(例如,没有打开所要求文件的足够权限). 当 UNIX 函数出错时,常常返回一个负值,而且将整型变量 errno 设置成含有附加信息的各个常量.例如,open 函数如果成功执行则返回一个非负文件描述符,如出错则返回 -1.在 open 出错时,有大约 1

UNIX环境编程学习笔记(19)——进程管理之fork 函数的深入学习

lienhua342014-10-07 在“进程控制三部曲”中,我们学习到了 fork 是三部曲的第一部,用于创建一个新进程.但是关于 fork 的更深入的一些的东西我们还没有涉及到,例如,fork 创建的新进程与调用进程之间的关系.父子进程的数据共享问题等.fork 是否可以无限制的调用?如果不行的话,最大限制是多少?另外,我们还将学习一个 fork 的变体 vfork. 1 fork 创建的新进程与调用进程之间的关系 UNIX 操作系统中的所有进程之间的关系呈现一个树形结构.除了进程 ID