TOP

系统调用IO和标准IO(一)
2019-09-19 11:10:34 】 浏览:50
Tags:系统 调用 标准

1. 系统调用IO(无缓冲IO)

系统调用

在Linux中一切皆文件,文件操作在Linux中是十分重要的。为此, Linux内核提供了一组用户进程与内核进行交互的接口用于对文件和设备进行访问控制,这些接口被称为系统调用。

系统调用对于应用程序最大的作用在于:

  • 以统一的形式,为应用程序提供了一组文件访问的抽象接口,应用程序不需要关心文件的具体类型,也不用关心其内部实现细节。

常用系统调用IO函数

常用的系统调用IO函数有5个:open、close、read、write、ioctl,此外还有个非系统调用IO函数lseek,系统调用IO都是不带缓冲的IO。

open

open用于创建一个新文件或打开一个已有文件,返回一个非负的文件描述符fd。
0、1、2为系统预定义的文件描述符,分别代表STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//成功返回文件描述符,失败返回-1
int open(const char *pathname, int flags, ... /* mode_t mode */);

flags参数一般在O_RDONLY、O_WRONLY和O_RDWR中选择指定一个,还可以根据需要或上以下常值:

  • O_CREAT:若文件不存在则创建它,此时需要第三个参数mode,mode可设的值及含义如下图所示。
  • O_APPEND:每次写时都追加到文件的尾端
  • O_NONBLOCK:如果pathname对应的是FIFO、块特殊文件或字符特殊文件,则该命令使open操作及后续IO操作设定为非阻塞模式

close

close用于关闭一个已打开文件。

#include <unistd.h>

//成功返回0,失败返回-1
int close(int fd);

进程终止时,内核会自动关闭它所有的打开文件,应用程序经常利用这一点而不显式关闭文件。

read

read用于从打开文件中读数据。

#include <unistd.h>

//成功返回读到的字节数;若读到文件尾则返回0;失败返回-1
ssize_t read(int fd, void *buf, size_t count);

read操作从文件的当前偏移量处开始,在成功返回之前,文件偏移量将增加实际读到的字节数。
有几种情况可能导致实际读到的字节数少于要求读的字节数:

  • 读普通文件时,在读到要求字节数之前就到达了文件尾。例如,离文件尾还有30字节,要求读100字节,则read返回30,下次在调用read时会直接返回0
  • 从网络读时,网络中的缓冲机制可能造成返回值少于要求读的字节数,解决办法在网络编程专题中再讲

write

write用于向文件写入数据。

#include <unistd.h>

//成功返回写入的字节数,失败返回-1
ssize_t write(int fd, const void *buf, size_t count);
  • write的返回值通常与参数count相同,否则表示出错。
  • 对于普通文件,write操作从文件的当前偏移量处开始
  • 若指定了O_APPEND选项,则每次写之前先将文件偏移量设置到文件尾
  • 成功写入之后,文件偏移量增加实际写的字节数。

lseek

lseek用于设置打开文件的偏移量。

#include <sys/types.h>
#include <unistd.h>

//成功返回新的文件偏移量,失败返回-1
off_t lseek(int fd, off_t offset, int whence);

对offset的解释取决于whence的值:

  • 若whence == SEEK_SET,则将文件偏移量设为距文件开头offset个字节,此时offset必须为非负
  • 若whence == SEEK_CUR,则将文件偏移量设为当前值 + offset,此时offset可正可负
  • 若whence == SEEK_END,则将文件偏移量设为文件长度 + offset,此时offset可正可负

注意:

  • lseek仅将新的文件偏移量记录在内核中,它并不引起任何IO操作,因此它不是系统调用IO,但该偏移量会用于下一次read/write操作
  • 管道、FIFO和套接字不支持设置文件偏移量,不能对其调用lseek

ioctl

ioctl提供了一个用于控制设备及其描述符行为和配置底层服务的接口。

#include <sys/ioctl.h>

//出错返回-1,成功返回其他值
int ioctl(int fd, int cmd, ...);
  • ioctl对描述符fd引用的对象执行由cmd参数指定的操作
  • 每个设备驱动程序都可以定义它自己专用的一组ioctl命令

2. 标准IO(带缓冲IO)

概述

标准IO其实就是stdio.h头文件中提供的IO接口,只不过在特定的系统中可能有特定的内部实现。
和系统调用IO类似,标准IO也预定义了三个文件指针stdin、stdout、stderr,分别对应标准输入、标准输出、标准错误。

缓冲与冲洗

标准IO是带缓冲的IO,一共有3种类型的缓冲:

  • 全缓冲:缓冲区填满后才进行IO操作,如磁盘文件
  • 行缓冲:遇到换行符才进行IO操作,如命令行终端(stdin和stdout)
  • 无缓冲:不经过缓冲,立即进行IO操作,如stderr

一般情况下,系统默认使用下列类型的缓冲:

  • stderr是无缓冲的
  • 指向终端设备的流是行缓冲的,否则是全缓冲的

对于一个打开的流,可以调用setbuf或setvbuf改变其缓冲类型.

//成功返回0,失败返回非0
void setbuf(FILE *fp, char *buf);
int setvbuf(FILE *fp, char *buf, int mode, size_t size);
  • setbuf用于关闭或打开fp的缓冲机制,若打开,则buf必须指向一个长度为BUFSIZ的缓冲区;若关闭,则buf设为NULL
  • setvbuf通过参数mode可精确设置缓冲类型,_IOLBF==全缓冲, _IOLBF==行缓冲,_IONBF==无缓冲
  • 当setvbuf设置为带缓冲时,buf必须指向一个长度为size的缓冲区,推荐将buf设为NULL让系统自动分配缓冲区长度,此时size可设为0

对于全缓冲和行缓冲,不管是否满足IO条件,都可以使用fflush函数强制进行IO操作,我们称其为冲洗。

//成功返回0,失败返回EOF
//若fp为NULL,将导致冲洗所有输出流
int fflush(FILE *fp);

常用标准IO函数

常用的标准IO函数分为以下几大类:

  • 打开和关闭流
  • 定位流
  • 读写流,包括文本IO、二进制IO和格式化IO三种

打开和关闭流

//成功返回文件指  
		
系统调用IO和标准IO(一) https://www.cppentry.com/bencandy.php?fid=103&id=261472

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇管道和FIFO 下一篇Linux五种IO模型