OSLab文件描述符
日期:2019/3/24
内容:Linux文件描述符。
一、基本概念
- 文件描述符(File Descriptor)
一个非负整数。应用程序利用文件描述符来访问文件。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
二、文件读写
- 头文件的解析
|
sys/stat.h |
status |
|
fcntl.h |
file control |
- int flags参数取值
必须取值:O_RDONLY、O_WRONLY、O_RDWR。
可选取值(两种取值通过 | 组合)
|
O_APPEND |
每次写操作都写入文件的末尾 |
|
O_CREAT |
如果指定文件不存在,则创建这个文件 |
|
O_EXCL |
如果要创建的文件已存在,则返回-1,并且修改errno的值 |
|
O_TRUNC |
如果文件存在,并且以只写/读写方式打开,则清空文件全部内容(即将其长度截短为0)(truncate,截断) |
|
O_NOCTTY |
如果路径名指向终端设备,不要把这个设备用作控制终端。 |
|
O_NONBLOCK |
如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继I/O |
- mode_t mode参数
|
参 数 |
说 明 |
参 数 |
说 明 |
|
S_IRUSR |
所有者拥有读权限 |
S_IXGRP |
群组拥有执行权限 |
|
S_IWUSR |
所有者拥有写权限 |
S_IROTH |
其他用户拥有读权限 |
|
S_IXUSR |
所有者拥有执行权限 |
S_IWOTH |
其他用户拥有写权限 |
|
S_IRGRP |
群组拥有读权限 |
S_IXOTH |
其他用户拥有执行权限 |
|
S_IWGRP |
群组拥有写权限 |
(数字表示法,例如chmod -r dir 777,777表示最高权限)
- 与文件相关的函数
|
int open(char *path, int flags, mode_t mode); |
·mode是文件权限标志 ·返回值:成功则返回文件描述符,否则返回-1 |
|
int openat(int dirfd, const char *pathname, int flags, mode_t mode); |
·用到时再补充 |
|
int read(int fd, void *buf, size_t size); |
·返回值成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0。 ·注意判断返回值与参数size的大小关系 |
|
int write(int fd, void *buf, size_t size); |
·返回实际写入的字节数,当有错误发生时则返回-1。 |
三、内核与文件管理
- 索引节点(Index Node, inode)
>>索引节点保存了文件的元信息数据,包括:文件大小,磁盘位置,创建和修改时间,所有者,访问权限。
- file结构体
>>一个file结构体表示一个打开的文件。
>>其包含的信息:对应的inode,文件当前的访问位置(即读写位置),打开模式,etc
- 文件描述符表
>>实质是一个数组,数组的元素类型是指针,指针指向一个file结构体。上文所述fd是数组下标。
>>用于保存被打开的文件。
>>内核打开文件时,分配一个file结构体表示被打开的文件,将该file结构体指针保存在文件描述符表中。
- 打开文件的过程
|
|
- 进程控制块(PCB)
>>进程控制块是操作系统表示进程状态的数据结构。
>>存放用于描述进程情况及控制进程运行所需的全部信息。包括:进程标识信息(PID)、处理机状态、进程调度信息、打开文件列表(即上文所述的文件描述符表,记录进程打开的文件)
>>私有的文件描述符表
>>>>文件描述符表对进程来说是私有的: 每个进程都有一个私有的文件描述符表; 操作系统有N个进程,则对应有N张文件描述符表。
>>>>两个进程打开不同的文件,文件描述符可能是相同的。进程A打开文件a.txt,open返回值是3;进程B打开文件b.txt,open返回值也可能是3。
>>实例代码
|
aopen.c |
bopen.c |
|
#include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int main() { int fd = open("aopen.c", O_RDONLY); printf("a fd = %d\n", fd); close(fd); return } |
#include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int main() { int fd = open("bopen.c", O_RDONLY); printf("b fd = %d\n", fd); close(fd); return } |
- 三个标准文件(stdin、stdout、stderr)
>>一切皆文件
>>stdin:标准输入文件,通常对应终端的键盘,进程的文件描述符表第0项
>>stdout:标准输出文件,通常对应终端屏幕,进程的文件描述符表第1项
>>stderr:标准错误输出文件,通常对应终端屏幕,进程的文件描述符表第2项
>>如果关闭2号文件stderr(即close(2)),再打开一个新文件fd,那么fd=2。
>>实例代码
|
int main() { char buf[256] = { 0 }; int len = read(0, buf, sizeof(buf)); write(1, buf, len); return } |
四、重定向
- 系统调用fork
>>创建一个子进程:为子进程创建一个独立的地址空间;为子进程创建一个独立的文件描述符表。
>>子进程复制父进程属性:代码段、数据段的内容;文件描述符表。
- 系统调用dup
>>原型:int dup(int oldfd);
>>功能:通过复制文件描述符oldfd,创建一个新的文件描述符newfd。newfd和oldfd指向相同的文件。
>>返回值:成功newfd,失败-1(如oldfd不是有效的描述符时)
>>成功后,newfd与oldfd不会共享fd_flags(例如the close-on-exec flag,close(newfd)之后,oldfd依然有效)
>>代码与图解
|
代码 |
dup前 |
dup后 |
|
int main() { int testfd = 6; int newtestfd = dup(testfd); printf("newtestfd = %d\n", newtestfd);
int oldfd = 2; const int newfd = dup(oldfd); write(newfd, str, strlen(str)); close(newfd); write(oldfd, str, strlen(str)); return } |
|
|
- 系统调用dup2
>>原型:int dup2(int old, int new)
>>功能:用new指定新描述符的值,如果new本身已经打开了,则会先将其关闭再将new指向old,最后返回new。如果old等于new,则返回new,并不关闭它。(简记:关new指old,可用于输出的重定向)
>>返回值:成功返回新复制的fd(即newfd),失败-1。如果old无效,返回-1。
>>重定向实例代码(将stderr重定向到文件log)
|
代码 |
图解 |
|
int main() { int fd = open("log", O_RDWR | O_CREAT); dup2(fd, 2); char *str = "Hello World...\n"; write(2, str, strlen(str)); close(fd); return } |
- 系统调用pipe(可以实现父子进程之间的通信)
>>原型:int pipe(int fd[2])
>>功能:创建一个可读写的管道,管道具备读端和写端。fd[0]是pipe的读端,fd[1]是管道的写端。
>>返回值:成功0,失败非0。
>>注意:管道中的buf一旦被读取,就没有了。(即:数据只能读取一次)
>>实例1
|
int main() { int fd[2] = {-1, -1}; pipe(fd); const char buf[256]; printf("read = %d, write = %d\n", fd[0], fd[1]); write(fd[1], str, strlen(str)); read(fd[0], buf, 255); printf("buf = %s\n", buf); close(fd[0]); close(fd[1]); } |
>>实例2(实现命令:cat pipe.c | wc)
|
int main() { int fd[2]; int pid; int status = 0; char buf[1024 * 2] = ""; pipe(fd); //must be at the front of fork() pid = fork();
if (pid == 0) { dup2(fd[1], 1); //stdout points to wirte pipe close(fd[0]); close(fd[1]); execlp("cat", "cat", "pipe2.c", NULL); exit(-1); }
wait(&status); if(status != 0) perror("execlp error...\n");
dup2(fd[0], 0); //stdin points to read pipe close(fd[0]); close(fd[1]); //read(0, buf, sizeof(buf) - 1); execlp("wc", "wc", NULL); printf("Are program getting here?\n"); return } 运行结果 如果把父进程中execlp前面的read加上 s 分析: ·pipe调用必须在fork之前,否则不会共享pipe ·父子进程中注意关闭不需要的fd[i](因为通常是一个进程读,一个进程写) ·pipe中buf的数据只能读取一次 |
图解: |
OSLab文件描述符的更多相关文章
- 文件描述符、文件表项指针、inode节点的关系
内核使用3种数据结构表示打开的文件,他们之间的关系决定了在文件共享方面一个进程对另一个进程的影响. (1) 每个进程在进程表中都有一个纪录项,纪录项中包含一张打开文件描述符表,每个文件描述符各占一项, ...
- Linux内核笔记--深入理解文件描述符
内核版本:linux-2.6.11 文件描述符(file descriptor)在Linux编程里随处可见,设备读写.网络通信.进程通信,fd可谓是关键中的关键. 深入理解可以增加我们使用它的信心. ...
- Linux 利用进程打开的文件描述符(/proc)恢复被误删文件
Linux 利用进程打开的文件描述符(/proc)恢复被误删文件 在 windows 上删除文件时,如果文件还在使用中,会提示一个错误:但是在 linux 上删除文件时,无论文件是否在使用中,甚至是还 ...
- Linux 文件描述符和重定向
200 ? "200px" : this.width)!important;} --> 介绍 文件描述符是与文件输入.输出相关联的整数,在编写脚本时会经常使用标准的文件描述符 ...
- linux专题一之文件描述符、重定向、管道符、tee命令
本节讨论一下几个问题: 1. 文件描述符. 2. 重定向. 3. 管道符 4. tee的用法. 1. 文件描述符. 在linux系统中一切皆文件.文件夹和设备都是文件.如何用来区别不同的文件呢?这里的 ...
- CentOS最大文件描述符限制更改
系统级的限制:/proc/sys/fs/file-max中设定了系统最大能打开的文件数. 查看该值可以用如下方式: [root@#panda ~]# cat /proc/sys/fs/file-max ...
- linux文件描述符open file descriptors与open files的区别
一个文件被打开,也可能没有文件描述符,比如current working diretories,memory mapped files and executable text files ;losf可 ...
- linux文件描述符数量的坑
ulimit -n 查看 单进程或线程,可打开的最大文件描述符数 通过ulimit -n 10240 设置文件描述符数: (当前shell生效,这真是个坑啊) 永久生效:(需要重启系统,也是个坑,好 ...
- Shell重定向文件描述符
#!/bin/bash 最近在看shell,各种困惑,不过解决困惑的感觉还是很不错的.废话少说,linux中使用文件描述符来标识每个文件对象.文件描述符为一个非负整数,可以唯一标识会话中打开 ...
随机推荐
- JWT设计实现
一.JWT基于token的认证流程: 二.JWT SDK的选取: https://jwt.io/ 三.编写JWT Helper: 1.获取token 设置密钥,规定算法,设置过期时间,设置发行方,生命 ...
- java测试ATM自助操作系统
开学第一周系主任安排了一项测试,测试要求:模拟ATM自助取款机用文件进行存储账户信息,密码等,并进行存款取款,转账,查询记录等操作,而且要进行文件的读取与录入. 这是一个ATM自助取款的操作系统,进行 ...
- crt转cer ,6.0以上的android系统证书请求配置
1.在服务器人员,给你发送的crt证书后,进到证书路径,执行下面语句 openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der 这样你就可以得到cer ...
- MPA(Macro Prudential Assessment)即宏观审慎评估体系
MPA(Macro Prudential Assessment)即宏观审慎评估体系.2015年12月29日,央行发布公告称,为进一步完善宏观审慎政策框架,更加有效地防范系统性风险,发挥逆周期调节作用, ...
- Spring MVC 3 表单中文提交post请求和get请求乱码问题的解决方法
在spring mvc 3.0 框架中,通过JSP页面.HTML页面以POST方式提交表单时,表单的参数传递到对应的servlet后会出现中文显示乱码的问题.解决办法可采用spring自带的过滤技术, ...
- 开机logo以及两种修改开机动画方法
Android开机画面总共有三屏 一.第一屏:开机logo 1.选张png格式的图片,在Linux任意下执行(安装工具): sudo apt-get install pnmtoplainpm 2.在所 ...
- python读取文件操作.CSV
#-*- encoding:utf-8 -*- import numpy as np import pandas as pd def test(): # header=0,表示文件第0行为列索引 # ...
- python计算机硬件基础以及变量常量常量池,解释器编译器比较,python的两种运行方式
1.什么是编程语言 语言是一个事物与另外一个事物沟通的介质 编程语言是程序员与计算机沟通的介质 2.什么是编程 编程就是程序按照某种编程语言的语法规范将自己想要让计算机做的事情表达出来 表达的结果就是 ...
- Alpha阶段敏捷冲刺(二)
1.提供当天站立式会议照片一张. 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 祁泽文:上网了解了艾宾浩斯遗忘曲线算法. 徐璐琳:找交互模块的源 ...
- SSM_CRUD新手练习(2)配置文件
配置之前现需要引入依赖的jar包: *Spring *SpringMvc *Mybatis *数据库连接池,驱动包 *其他(jstl,Servlet ,Junit..) 1.poxm.xml < ...