您的位置:首页 > 编程语言 > C语言/C++

标准IO

2017-10-29 19:32 127 查看
一、Linux文件I/O

1、POSIX规范

POSIX(Portable Operating System Interface,可移植操作系统接口规范)标准最初由IEEE(Institute of Electrical and Electronics Engineers,电气和电子工程师协会,是目前最大的全球性非营利性专业技术学会)制定,目的是提高UNIX环境下程序的可移植性。通俗来讲,为一个兼容POSIX标准的操作系统编写的应用程序,可以在任何其他兼容POSIX标准的操作系统上编译执行而无需修改代码。常见的Linux与UNIX系统都支持POSIX标准。

2、虚拟文件系统VFS

Linux系统的一个成功的关键因素是它具有与其他操作系统共存的能力。Linux的文件系统由两层结构搭建:上面的虚拟文件系统VFS(Virtual File System),和下面的各种不同的具体文件系统(例如Ext、FAT32、NFS等)。见附图。

VFS将各种具体的文件系统的公共部分抽取出来形成一个抽象层,位于用户的程序与具体需要使用的系统中间,并提供系统调用接口。这样我们只需针对VFS提供的系统调用进行文件操作而无需具体考虑底层细节。VFS屏蔽了用户对底层细节的描述使得编程简化。

可以使用指令

cat /proc/filesystems

查看当前操作系统支持哪些具体文件系统。

3、文件与文件描述符

Linux操作系统是基于文件概念搭建起来的操作系统(“万物皆文件”),基于这一点,所有的I/O设备都可以直接当做文件来处理。因此操作普通文件的操作函数与操作设备文件的操作函数是相同的,这样大大简化了系统对不同设备、不同文件的处理,提高了效率。

那么对于内核而言,内核是如何区分不同的文件呢?内核使用文件描述符来索引打开的文件。文件描述符是一个非负整数,每当打开一个存在的文件或创建一个新文件的时候,内核会向进程返回一个文件描述符,当对文件进行相应操作的时候,使用文件描述符作为参数传递给相应的函数。

通常一个进程启动时,都会打开三个流:标准输入、标准输出、标准错误输出,这三个流的文件描述符分别是0、1、2,对应的宏定义是STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。可以查看头文件unistd.h查看相关定义。

流的名称 文件描述符
宏定义

标准输入 0
STDIN_FILENO

标准输出 1
STDOUT_FILENO

标准错误输出 2
STDERR_FILENO

基于文件描述符的I/O操作虽然不能直接移植到诸如Windows系统等之外的操作系统上,但对于某些底层的I/O操作(例如驱动程序、网络连接等)是唯一的操作途径。

4、标准I/O与文件I/O的区别:

1.文件I/O又称为低级磁盘I/O,遵循POSIX标准。任何兼容POSIX标准的操作系统都支持文件I/O。标准I/O又称为高级磁盘I/O,遵循ANSI C相关标准。只要开发环境有标准C库,标准I/O就可以使用。

在Linux系统中使用GLIBC标准,它是标准C库的超集,既支持ANSI C中定义的函数又支持POSIX中定义的函数。因此Linux下既可以使用标准I/O,也可以使用文件I/O。

2.通过文件I/O读写文件时,每次操作都会执行相关系统调用。这样的好处是直接读写实际文件,坏处是频繁的系统调用会增加系统开销。标准I/O在文件I/O的基础上封装了缓冲机制,每次先操作缓冲区,必要时再访问文件,从而减少了系统调用的次数。
3.文件I/O使用文件描述符打开操作一个文件,可以访问不同类型的文件(例如普通文件、设备文件和管道文件等)。而标准I/O使用FILE指针来表示一个打开的文件,通常只能访问普通文件。

二、文件I/O编程

1、打开文件

函数open()

需要头文件:#include<sys/stat.h>

            #include<fcntl.h>

函数原型:int open(const char *pathname,int flags,int perms);

函数参数:pathname:打开文件名(可以包含具体路径名)

          flags:打开文件的方式,具体见下
 perms:新建文件的权限,可以使用宏定义或者八进制文件权限码,具体见下

函数返回值:成功:文件描述符

            失败:-1

参数2flags具体可用参数(若使用多个flags参数可以使用|组合):
O_RDONLY:以只读方式打开文件
O_WRONLY:以只写方式打开文件
O_RDWR:以可读可写方式打开文件
O_CREAT:如果文件不存在,就创建这个文件,并使用参数3为其设置权限
O_EXCL:如果使用O_CREAT创建文件时文件已存在则返回错误信息。使用这个参数可以测试文件是否已存在
O_NOCTTY:若打开的是一个终端文件,则该终端不会成为当前进程的控制终端
O_TRUNC:若文件存在,则删除文件中全部原有数据并设置文件大小为0
O_APPEND:以添加形式打开文件,在对文件进行写数据操作时数据添加到文件末尾
注意:O_RDONLY与O_WRONLY与O_RDWR三个参数互斥,不可同时使用

若在参数2的位置有多个参数进行组合,注意使用按位或(|)运算符。

/** 可查看/usr/include/i386-linux-gnu/bits/fcntl.h文件看到具体的宏定义 **/

参数3perms表示新建文件的权限,可以使用宏定义或八进制文件权限码。其中宏定义的格式是:S_I(R/W/X)(USR/GRP/OTH),其中R/W/X代表可读/可写/可执行,USR/GRP/OTH代表文件所有者/文件组/其他用户。例如:

S_IRUSR|S_IWUSR表示设置文件所有者具有可读可写权限,即0600。(一般情况下该参数都直接使用八进制文件权限码因为使用宏定义的形式太复杂)。

2、关闭文件

函数close()

需要头文件:#include<unistd.h>

函数原型:int close(int fd);

函数参数:fd:文件描述符

函数返回值:成功:0

            失败:-1

3、文件读写

函数read()

需要头文件:#include<unistd.h>

函数原型:int read(int fd,void *buf,size_t count);

函数参数:fd:文件描述符

          buf:读取出的数据存放的缓冲区
 count:指定读取的字节数

函数返回值:成功:读到的字节数 或 0(表示文件已结尾)

            失败:-1

函数write()

需要头文件:#include<unistd.h>

函数原型:ssize_t write(int fd,void *buf,size_t count);

函数参数:fd:文件描述符

          buf:待写入的数据存放的缓冲区
 count:指定写入的字节数

函数返回值:成功:已写的字节数

            失败:-1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  文件IO IO C语言