基础IO与文件描述符
来源:互联网 发布:ubuntu 调整时区 编辑:程序博客网 时间:2024/05/24 11:13
一、引题
之前我们讲过C标准库提供的IO函数fread,fwrite等,那么它们到底是怎么实现的呢?它们是真的靠自己写出来的吗?不一定?
我们先来看看关于操作系统的概念图
从中我们可以看出C标准库属于用户部分,是给用户的操作接口,不过这个接口它又是来源于系统调用接口,可以看成他是系统调用的封装,那我们探究一下我们之前提到的c标准库给我们提供的函数fopen(),它封装了那个系统调用的那个接口呢?百度之后发现它其实封装的是open(),我们在Linux下man open,我们发现接口的原型有两种:
int open(const char *pathname, int flags);
功能:打开和创建文件
参数:pathname:待打开/创建文件的路径名 flags:打开模式()
O_RDONLY只读模式
O_WRONLY只写模式
O_RDWR读写模式
以上三种常量必须选一个,下面的是非必须选,下面这些和上面这些或(|)起来构成完整的打开模式
O_APPEND每次写操作都写入文件的末尾
O_CREAT如果指定文件不存在,则创建这个文件
O_EXCL如果要创建的文件已存在,则返回-1,并且修改errno的值
O_TRUNC如果文件存在,并且以只写/读写方式打开,则清空文件全部内容(即将其长度截短为0)
O_NOCTTY如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继I/O
返回值:成功则返回文件描述符,否则返回-1
int open(const char *pathname, int flags, mode_t mode);
这个与上面基本一致,只是多了个标志位 这个标志位是用来创立新文件时候,给新文件定各个用户权限的
mode 是一个是一个无符号八进制数,为什么呢,这个就要和chmod联系起来,我们当初设置权限数字的每一位代表一类权限。用户所获得的权限是加权数值的总和。例如764表示所有者拥有读、写和执行权限,群组拥有读和写权限,其他用户拥有读权限。所以同样的,这里的mode也是同样的意思。
ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读数据
参数:fd:文件描述符 buf:保存数据的起始地址 count:指定的字节数
返回值:成功返回读文档的字节数,失败返回-1,当读到EOF,返回0
ssize_t write(int fd, const void *buf, size_t count);
功能:从打开文件中读数据
参数:fd:文件描述符 buf:指定缓冲区 count:指定的字节数
返回值:成功返回写文档的字节数,失败返回-1
By:注意write和read返回值类型是有符号长整型,这样才可以返回负数,达到报错的目的二、文件描述符
运行环境:gcc (GCC) 4.4.7
代码:
#include <stdio.h>#include <string.h>#include <fcntl.h>#include <unistd.h>//fd连续分配void Test1(){umask(0);int fd1 = open("./myfile1",O_RDONLY|O_CREAT,0666);if(fd1==-1)printf("open Error\n"); int fd2 = open("./myfile1",O_RDONLY|O_CREAT,0666); if(fd2==-1)printf("open Error\n"); printf("fd1 = %d fd2 = %d\n",fd1,fd2); close(fd1); close(fd2);}//fd从最小的开始分配void Test2(){umask(0);int fd1 = open("./myfile1",O_RDONLY|O_CREAT,0666);if(fd1==-1)printf("open Error\n");printf("fd1 = %d\n",fd1);close(fd1); int fd2 = open("./myfile2",O_RDONLY|O_CREAT,0666); if(fd2==-1)printf("open Error\n"); printf("fd2 = %d\n",fd2); close(fd2);}int main(){ //Test1(); Test2(); return 0;}
Test1()运行结果:
fd1 = 3 fd2 = 4
Test2()运行结果:
fd1 = 3
fd2 = 3
从这两个运行结果我们可以看出,fd按照从小到大依次分配下标,总是选择在当前情况下最小的一个下标进行分配,作为新的文件描述符,但是我们又有了新的问题,为什么从3开始分配呢?那0,1,2去干嘛了,经过查找,原来0,1,2分别对应着标准输入,标准输出,标准错误,Linux进程默认情况下会打开的文件描述符既然有了这个,那我们就可以利用这种特性改善过去的输出和输入
#include <stdio.h>#include <fcntl.h>#include <string.h>int main(){char* buf ="hello fd!";write(1, buf, strlen(buf));write(2, buf, strlen(buf));return 0;}
运行结果:
hello fd!
通过这里,我们发现利用这种文件描述符,也可以完成向屏幕输入和打印的功能#include <stdio.h>int main(){close(1);int fd = open("./test.txt",O_RDONLY|O_CREAT);if(fd==-1){printf("Error\n");}printf("fd = %d\n",fd);close(fd);return 0;}:
运行结果:
fd = 1
顺便补充下,当我们关闭0,依然符合我们之前总结的,从第一个空闲的最小的下标开始分配的规则。并且最为关键的是实现了重定向,这下相当于之前向屏幕输出的数据,以后都会输出到我们所创建的这个test.txt文件中注意事项:
open()过后,一定要记得close(),否则会造成资源泄漏,为什么呢,这就需要谈到文件描述符,我们首先来看下面这张图,了解下fd存在意义
我们将文件描述符简称为fd,从这张图,我们可以看出fd其实是fd_array这个数组的下标,在一般情况下,进程默认打开标准输入,标准输出,标准错误,它们的下标分别是0,1,2,之后的下标是为我们预留,供用户使用的,如果我们不close,那么fd_array数组就会使用完,导致资源泄露。
总结下:从这个文件描述符也让我们了解了Linux的重要思想,一切皆文件,不管是普通文件,目录,字符设备,块设备,套接字,在Linux中都是以文件被对待,它们虽然类型不同,但是对其提供的确实同一套操作模式
- 基础IO与文件描述符
- 文件描述符与Linux文件IO
- Linux——makefile IO基础 文件描述符
- 6-文件IO-文件描述符与lseek
- 【转载】IO重定向与文件描述符
- UNIX IO---文件描述符
- Linux编程基础:文件描述符file descriptor与inode
- 《UNIX IO---再谈文件描述符》
- UNIX IO---再谈文件描述符
- UNIX IO---再谈文件描述符
- UNIX IO---再谈文件描述符
- UNIX IO---再谈文件描述符
- UNIX IO---再谈文件描述符
- UNIX IO---再谈文件描述符
- UNIX IO---再谈文件描述符
- 文件描述符与进程描述符
- exec与文件描述符
- socket与文件描述符
- C语言函数声明问题。
- ps进行透视变换(扭曲变换)
- IoT时代下可穿戴设备命运几何?
- php 导出excel文件
- matlab曲线拟合 函数 用法以及例子
- 基础IO与文件描述符
- Kotlin核心技术详解视频课程
- Linux strace 跟踪进程信息
- 20-IO流(字符流-缓冲区-LineNumberReader了解 21-IO流(字节流-操作文件基本演示). 22-IO流(字节流-练习-复制MP3)
- 记录上次访问时间
- 【文智背后的奥秘】系列篇——海量数据抓取
- I/O 输入输出流
- AI 技术与伦理
- 大数据24小时:云计算创企“云途腾”获1.08亿元融资,百度设立20亿元AI风投基金