文件描述符

1、文件描述符的概念

对于内核而言,所有打开的文件都会用一个文件描述符来引用,打开或和创建一个新文件的时候,内核会给进程返回一个文件描述符,而当使用read write时,可以使用这个文件描述符来代替文件。

UNIX系统下,使用0 1 2 来分别与标准输入 标准输出 标准出错输出相关联。

2、文件操作有关的函数

open函数

  /*fcntl.h定义了很多宏和fcntl函数原型*/
#include <fcntl.h>
int open(const char *pathname ,int oflag,/*mode_t mode*/); /*例子*/
int fd = open("a.txt",O_RDONLY)
if(fd ==-1)
return -1;

函数的参数:

pathname:需要打开或者创建文件的路径

oflag:此参数的多个选项

mode:当oflag = O_CREAT 时,需要额外指定的参数,用来表示新创建文件的访问权限位如0777

函数的返回值:

成功返回文件描述符,失败返回 -1

oflag可选的选项:

O_APPEND 每次写都追加到文件的末端

O_CREAT 如果文件不存在就创建一个

O_TRUNC 如果此文件存在而且是以读和写的形式打开,就把他的文件长度截断到0

O_DSYNC 使每次write等待物理io操作完成,但是如果写操作不影响读取则不等待

O_RSYNC 让每一个read操作等待,直到对文件同一部分的写操作完成

O_RDONLY O_WRONLY O_RDWR 只读打开 只写打开 读写打开

open返回的文件描述符一定是最小的文件描述符

close函数

  #include<unistd>
int close(int fd);

返回值:

成功返回0,失败返回-1

关闭一个文件还会清除这个文件的记录锁

当一个进程终止时,内核会自动关闭进程打开的文件

lseek函数

每个打开的文件都有其文件偏移量,通常是一个非负数,读写操作都会从这个当前偏移量开始,每读或者写一字节,文件偏移量后移一字节

  #include<unist.h>
off_t lseek (int fd, off_t offset,int whence);

参数:

fd: 需要被修改文件偏移量的文件描述符

whence:

SEEK_SET 文件偏移量设为距离文件开始处offset字节

SEEK_CUE 文件偏移量设为当前值处offset字节

SEEK_END 文件偏移量设为距离文件末尾处offset字节

返回值:

成功返回新的文件偏移量,出错就返回 -1

如果文件描述符引用的是一个管道 FIFO或网络套接字,lseek返回-1,并将errno设置为ESPIPE

lseek把当前文件的偏移量记录在内核,不会引起io操作

  #include<fcntl>
#include"apue.h"
char buf[] = "asdfg"
char buf[] = "ASDFG"
int main ()
{
int fd;
if ((fd = open ("a.txt",O_WDWR | O_CREAT,FILE_MODE))<0)
err_sys("creat err");
if(write(fd,buff1, 5) != 5)
err_sys("buff1 write err");
/*会制造一个空洞*/
if(lseek(fd,10 ,SEEK_SET) == -1)
err_sys ("lseek err ");
if(write(fd,buff2, 5) != 5)
err_sys("buff2 write err");
exit(0);
}

read函数

调用read可以从打开的文件中读取数据

  #include <unistd.h>
ssize_t read(int fd , void *buff ,size nbyte);

参数:

fd:文件描述符

buff:文件要读到哪里去

nbyte:文件要读多少字节

返回值:

读取成功则返回读取的字符,失败就返回-1

当没有读完要求的字节就已经到达文件末尾,直接返回已经读取的文件数。此时文件偏移量在末尾,继续调用read只会返回0

write函数

调用write函数向打开的文件写数据

  #include<unistd.h>
size_t write(int fd , const void *buff ,size nbyte);

参数:

fd:文件描述符

buff:文件要把哪里的数据写入

nbyte:文件要写多少字节

返回值:

写入成功就返回已经写入的字节数,失败就返回-1

返回值一般要和 nbyte 相同,不然就显示出错,出错的原因一般是:磁盘已经写满,超过了一个给定进程的文件长度限制

io的效率

  #include "apue.h"

  #define	BUFFSIZE	4096

  int
main(void)
{
int n;
char buf[BUFFSIZE];
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error"); exit(0);
}

上述函数把标准输入复制到标准输出,但对于不同的BUFFSIZE,程序运行的时间是不一样的

一般来讲,系统cpu时间随着BUFFSIZE的增大而减小(越来越快),而最大值出现在4096,继续增大不会对系统cpu时间产生更大的影响

文件共享

内核用三种数据结构来表示打开的文件:

  • 每个进程都会在进程表中有一个记录项,记录项中包含有一张这个进程打开的文件表,文件表中每一项包含文件描述符,和一个指向文件表项的指针
  • 内核为所有已经打开的文件维持了一个文件表,每个文件表项包括:文件状态标志 当前文件偏移量 指向该文件v节点表项的指针
  • v节点表项包含了v节点信息 i节点信息 当前文件长度

如果有两个独立进程各自打开了同一个文件,打开该文件的每一个进程都会得到一个文件表项:每个进程都有独立的文件偏移量

每个文件都只有一个v节点表项

也有共享同一个文件表项的情况:fork()之后的父子进程

原子操作

原子操作是独立的一个个体,要么全都完成,要么一点都不做。

dup和dup2函数

  #include<unist.h>
int dup(int fd);
int dup(int oldfd,int newfd);

dup函数:内核在进程中创建一个新的文件描述符,此描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项。

dup2函数:用newfd参数指定新描述符的数值,如果newfd已经打开,则先将其关闭。如果newfd等于oldfd,则dup2返回newfd, 而不关闭它。dup2函数返回的新文件描述符同样与参数oldfd共享同一文件表项。

sync fsync fdatasync函数

unix内核也存在一块缓冲区,被称为update的系统守护进程会周期性的调用sync,当数据写入文件时,内核把数据复制到其中一个缓冲区,如果该缓冲区满了,派入输出队列,没有满则等待

  #incude<unist.h>
/*把所有修改过的块缓冲区送到队列,不等待写磁盘操作结束*/
void sync;
/*只对单一文件有效果,等待写磁盘操作结束*/
int fsync(int fd);
/*只对数据有效,其他同fsync*/
int fdatasync(int fd);

/dev/fd

打开/dev/fd/n 和复制描述符n等效。

unix环境高级编程第三章笔记的更多相关文章

  1. UNIX环境高级编程-第三章习题

    1,当读写磁盘文件时,read,write等函数确实是不带缓冲机制的吗?请说明原因. 答:所有磁盘I/O都要经过内核的块缓存区(即内核的缓冲区高速缓存).唯一例外的是对原始磁盘设备的I/O,但是我们不 ...

  2. unix环境高级编程第六章笔记

    口令文件 阴影口令 组文件 附属组ID 登录账户记录 系统标识 口令文件<\h2> /etc/passwd文件是UNIX安全的关键文件之一.该文件用于用户登录时校验用户的口令,文件中每行的 ...

  3. unix环境高级编程第四章笔记

    文件和目录 start fstart lstart函数 一旦给出pathname, start函数就返回了与此命名文件有关的信息结构 #include <sys/start> int st ...

  4. 【转】apue《UNIX环境高级编程第三版》第一章答案详解

    原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...

  5. Linux - Unix环境高级编程(第三版) 代码编译

    Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...

  6. Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题

    学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...

  7. UNIX环境高级编程 第8章 进程控制

    本章是UNIX系统中进程控制原语,包括进程创建.执行新程序.进程终止,另外还会对进程的属性加以说明,包括进程ID.实际/有效用户ID. 进程标识 每个进程某一时刻在系统中都是独一无二的,它们之间是用一 ...

  8. UNIX环境高级编程 第7章 进程环境

    本章涉及C/C++程序中main函数是如何被调用的.命令行参数如何传递给main函数.程序的内存空间布局.程序如何使用环境变量.程序如何终止退出. main函数 C程序或C++程序总是从main函数开 ...

  9. UNIX环境高级编程 第4章 文件和目录

    第三章说明了关于文件I/O的基本函数,主要是针对普通regular类型文件.本章描述文件的属性,除了regular文件还有其他类型的文件. 函数stat.fstat.fstatat和lstat sta ...

随机推荐

  1. 免费、开源的基于tp5的快速开发框架

    HisiPHP 系统官网:https://www.hisiphp.com/ 后台体验:http://v2.demo.hisiphp.com/admin.php/system/publics/index ...

  2. oracle 11.2.0.1.0 升级 11.2.0.4.0 并 patch 到11.2.0.4.7

    升级步骤: (1)    备份数据库 (2)    运行patchset,升级oracle 软件 (3)    准备新的ORACLE_HOME (4)    运行dbua 或者脚本升级实例 (5)   ...

  3. python中列表的insert和append的效率对比

    python中insert和append方法都可以向列表中插入数据只不过append默认插入列表的末尾,insert可以指定位置插入元素. 我们来测试一下他俩插入数据的效率: 测试同时对一个列表进行插 ...

  4. HAProxy + keepalived 高可用集群代理

    HAProxy + keepalived # 1 安装keepalived: yum install keepalived -y # 2 修改KEEPalived配置文件: vim /etc/keep ...

  5. (十七)logging模块

    logging模块是Python内置的标准模块,主要用于输出运行日志. 简单应用 import logging logging.debug('+++debug+++') logging.info('+ ...

  6. linux线程库

    linux 提供两个线程库,Linux Threads 和新的原生的POSIX线程库(NPTL),linux threads在某些情况下仍然使用,但现在的发行版已经切换到NPTL,并且大部分应用已经不 ...

  7. 【Oracle】11g direct path read介绍:10949 event、_small_table_threshold与_serial_direct_read

    转自刘相兵老师的博文: http://www.askmaclean.com/archives/11g-direct-path-read-10949-_small_table_threshold-_se ...

  8. 环境变量IFS

    环境变量IFS的值是由1个空格.1个制表符.1个换行符依序构成的字符串,也就是" \t\n"字符串. #查看IFS变量值的长度: test ~ # expr length &quo ...

  9. SAP GUI用颜色区分不同的系统

    对于经常打开多个窗口的SAP用户,有时候可能同时登录了生产机.测试机和开发机,为了避免误操作,比如在测试要执行的操作,结果在生产机做了,结果可想而知. 虽然可以通过右下角查看再去判断,但是总是没有通过 ...

  10. 5V-12V输入输出的限流芯片,可调限至4.8A

    可是在输出电压模式:3.6V,5V,12V 在输出3.6V模式:输入电压范围2.5V-4.5V,输入关闭电压5V,限流最大4.8A 在输出5V模式,输入电压范围3.8V-6V,输输入过电压关闭6V,限 ...