文件描述符

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. 使用sublime text3搭建Python编辑环境

    最近在工作遇到一个难题. 我所在的测试组有一套PC软件前端自动化工程,在进行自动化测试时,需要在一台古老的xp机器上运行,但这台古老的xp机器带给我诸多烦恼,特别是使用Pycharm编辑器时,我遇到了 ...

  2. VMware 16.1虚拟机安装

    VMware 16.1创建虚拟机 1.1首先打开我们安装好的VMware点击创建新的虚拟机 典型为自动安装,接口位默认 自定义安装更自由,可以把按需求选择 VMware16版本,只能选择Worksta ...

  3. 值得推荐的C#不同版本语言特性

    C#语言在不断地版本升级中,为我们提供了很多新的语言特性.其中,有很多使用的语言特性,我觉得在实际开发中用起来很方便,能够简化我们的代码,增强可读性,提高开发效率. 小编不才,在这里给大家整理了一些实 ...

  4. es6 Array.from + new Set 去重复

    // es6 set数据结构 生成一个数据集 里面的元素是唯一的 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); // items 是个对象 item ...

  5. python模块详解 | selenium(持续更新中)

    目录: 关于selenium Selenium 安装Selenium 安装浏览器驱动 配置环境变量 selenium方法详解 定位元素 元素操作 浏览器操作 鼠标事件 浏览器事件 设置元素等待 多表单 ...

  6. spring boot gateway 过滤器的执行顺序

    前言 学习官方文档,发现对于过滤器有分为三类 默认过滤器 自定义过滤 全局过滤器 于是就有一个疑问,关于这些过滤器的访问顺序是怎样的,今天就以一个demo来进行测试 准备阶段 过滤器工厂类 以此为模板 ...

  7. FlatBuffers使用小结

    最近做一个Android APP,由于离线业务需求,需要在启动APP时候同步大量数据到APP上,遇到了JSON性能瓶颈.从下方的图片中可以看出,当使用 json 传输数据,在解析json的时候会产生大 ...

  8. CTFHub - Web(五)

    eval执行: 1.进入网页,显示源码, <?php if (isset($_REQUEST['cmd'])) { eval($_REQUEST["cmd"]); } els ...

  9. canvas性能-drawImage渲染图片

    canvas性能-绘制图片 目录 canvas性能-绘制图片 canvas绘制图片 drawImage putImageData createPattern 测试绘制耗时 drawImage Imag ...

  10. Visual Studio中自定义代码段!

    Visual Studio中自定义代码段! 第一步:在编辑器中进行快捷键的输入[ctrl + shift + p] 或者 点击 查看 第一个选项就是!请看下图 第二步:选择你要配置代码段的语言, 这里 ...