1.标准C的I/O

1.1常用函数和结构体

 char *fgets(char *s, int size, FILE *stream);  //整行输入
int printf(const char *format, …);
int fprintf(FILE *stream, const char *format, …);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
typedef struct iobuf{
int cnt; //剩余的字节数
char *ptr; //下一个字符的位置
char *base; //缓冲区的位置
int flag; //文件访问模式
int fd; //文件描述符
}FILE;

标准I/O函数都是带缓存的。

stdin:标准输入,针对键盘

stdout:标准输出,针对屏幕

stderr:标准出错,针对屏幕

三个都是FILE类型的结构体指针,成为流指针

1.2标准C的IO缓存类型

1.全缓存

要求填满整个缓冲区后才进行I/O系统调用操作,对于磁盘文件通常使用全缓存访问。

2.行缓存

涉及一个终端时(例如标准输入和标准输出),使用行缓存;

行缓存满自动溢出;

碰到换行符自动输出。

行缓存案例line_buffer.c

3.无缓存

标准错误流stderr通常是不带缓存的,这使得错误信息能够尽快的显示出来。

2.文件I/O系统调用

2.1常用函数

打开文件:open()

创建文件:create()

关闭文件:close()

读取文件:read()

写入文件:write()

文件定位:lseek()

这些不带缓存的函数都是内核提供的系统调用,他们不是ANIC C的组成部分,是POSIX的组成部分。

系统调用与C库的差异:

标准库函数:遵循ISO标准,基于流的I/O,对文件指针(FILE结构体)进行操作。

系统调用:兼容POSIX标准,基于文件描述符的I/O,对文件描述符进行操作。

2.2 文件描述符

对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数,当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用open或create返回的文件描述符标识该文件,将其作为参数传给read或write。

在POSIX应用程序中,整数0、1、2被替换成符号常数STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO。这些常数都定义在头文件<unistd.h>中。

文件描述符的范围是0-OPEN_MAX。Linux为1024

2.3 文件描述符和文件指针之间的转换

标准文件指针:

stdin 0

stdout 1

stderr 2

文件指针和文件描述符之间的转换函数:

FILE *fdopen(int fd, const char *mode); //文件描述符=>文件指针(fd=>FILE*)

int fileno(FILE *stream); //文件指针=>文件描述符(FILE *=>fd)

2.4 常用I/O系统调用函数说明

(1)open函数

 #include <sys/types.h> //头文件标准路径/usr/include
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

返回:若成功返回文件描述符,出错返回-1

功能:打开或创建一个文件

参数:pathname:要打开或创建的文件路径

flags:用来说明此函数的多个选择项,O_RDONLY只读,O_WRONLY只写,O_RDWR读写

mode:新建文件的访问权限,对于open函数而言,仅当创建新文件时才使用第三个参数。

注:用下列一个或多个常数进行或运算构成flags参数(这些常数定义在<fcntl.h>头文件中)

O_RDONLY以只读方式打开文件

O_WRONLY以只写方式打开文件

O_RDWR以读写方式打开文件

O_APPEND以追加模式打开文件,每次写时都追加到文件的尾端,但在网络文件系统进行操作时没有保证

O_CREAT如果指定的文件不存在,则按照mode参数指定的文件权限来创建文件

O_EXCL如果同时指定了O_CREAT,而文件已经存在,则出错。这可测试一个文件是否存在,但在网络文件系统进行操作时没有保证

O_DIRECTORY如果参数pathname不是一个目录,则open出错

O_TRUNC如果此文件存在,而且为只读或只写成功打开,否则将其长度截短为0

O_NONBLOCK如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置为非阻塞方式

(2)create函数

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int create(const char *pathname, mode_t mode);

返回:若成功为只写打开的文件描述符,若出错为-1

此函数等效于open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode);

create的一个不足之处是它以只写方式打开所创建的文件。

(3)close函数

 #include <unistd.h>
int close(int fd);

返回:若成功返回0,若出错返回-1

功能:关闭一个打开的文件。

(4)read函数

 #include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

返回:读到的字节数,若已到文件尾为0,若出错为-1

功能:从文件中读取数据。

参数:fd:读取文件的文件描述符指针

buf:存放读取数据的缓存

count:要求读取一次数据的字节数

有多种情况可使实际读到的字节数小于要求读字节数

  1. 读普通文件时,当读到要求字节数之前已达到了文件尾端
  2. 当从终端设备读时,通常一次最多读一行
  3. 当从网络读时,网络中的缓冲机制可能造成返回值小于所要求读的字节数
  4. 某些面向记录的设备,例如磁带,一次最多返回一个记录
  5. 进程由于信号造成中断

读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数。

(5)write函数

 #include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

返回:若成功返回写的字节数,若出错返回-1

功能:向打开的文件中写数据

参数:fd:写入文件的文件描述符

buf:存放待写数据的缓存

count:要求写入一次数据的字节数

若返回值通常与count的值不同,表示出错

write出错的一个常见原因:磁盘已写满或者超过了对一个给定进程的文件长度限制

对于普通该文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEDN选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处,在一次成功写之后,该文件位移量增加实际写的字节数。

(5)lseek函数

 #include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

返回:若成功则返回新的文件偏移量(绝对偏移量:相对起始位置),若出错返回-1

功能:定位一个已打开的文件

参数:fd:已打开文件的文件描述符

offset:位移量

whence:定位的位置,基准点。SEEK_SET:将该文件的位移量设置为距文件开始处offset个字节;SEEK_CUR:将文件的位移量设置为其当前值加offset,offset可正可负;SEEK_END:将该文件的位移量设置为文件长度加offset,offset可正可负,正数表示一个空洞文件。

lseek也可用来确定所涉及的文件是否可以设置位移量,如果文件描述符引用的是一个管道或FIFO,则lseek返回-1,并将errno设置为EPIPE。

每个打开的文件都有一个与其相关联的"当前文件偏移量"。它是一个非负整数,用以度量从文件开始处计算的字节数。通常读、写操作都从文件偏移量处开始,并使偏移量加所读或写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0。

文件读写buffer的大小一般设置为磁盘块的大小,磁盘块的大小可以通过命令查看:

df -k查看分区

sudo tune2fs -l /dev/sda1其中有个信息是:Block size: 4096

(6)dup和dup2函数

 #include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);

返回:成功返回新文件描述符,出错返回-1

功能:文件描述符的复制

参数:oldfd:原先的文件描述符;newfd:新的文件描述符

说明:由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。

用dup2则可以用newfd参数指定新描述符的数值,如果newfd已经打开,则先将其关闭,若oldfd等于newfd,则dup2返回newfd,而不关闭它。

在进程间通信时可用来改变进程的标准输入和标准输出设备。

cat < 输入重定向文件 > 输出重定向文件 >> 追加输出重定向文件

dup2复制过程:

(7)fcntl函数

 #include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct float *lock);

返回:若成功则依赖于cmd,若出错返回-1

功能:可以改变已经打开的文件性质

常见的功能:复制一个现存的描述符,新文件描述符作为函数值返回(cmd=F_DUPFD);

获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD);

获取/设置文件状态标志(cmd=F_GETFL或F_SETFL);

获取/设置文件锁(cmd=F_SETLK、cmd=F_GETLK、F_SETLKW)第三个参数为struct flock结构体。

cmd的常见取值:

F_DUPFD:复制文件描述符,新的文件描述符作为函数返回值返回

F_GETFD/F_SETFS:获取/设置文件描述符,通过第三个参数设置(arg)

F_GETFL/F_SETFL:获取/设置文件状态标志,通过第三个参数设置(arg),可以更改的几个标志是:O_APPEDN、O_NONBLOCK、O_SYNC、O_ASYNC(O_RDONLY、O_WRONLY和O_RDWR不适用)

给文件上锁:cmd:F_SETLK(非阻塞式)、F_GETLK和F_SETLKW(阻塞式)

 struct flock{
  short l_type;
  off_t l_start;
  short l_whence;
  off_t l_len;
  pid_t l_pid;
};

l_type:锁类型,F_RDLCK(共享读锁)、F_WRLCK(独占性写锁)或F_UNLCK(解锁一个区域)。

l_start、l_whence:要加锁或解锁的区域的起始地址,由l_start和l_whence两者决定,l_start是相对位移量,l_whence则决定相对位移量的起点。

l_len:表示区域的长度。

(9)ioctl函数

 #include <unistd.h>
#include <sys/ioctl.h>
int ioctl(int fd, int request, …);

返回:若成功则为其他值,出错返回-1

说明:I/O操作的杂物箱。不能用其他函数表示的I/O操作通常都能用ioctl表示,终端I/O是ioctl的最大使用方面,主要用于设备的I/O控制。

IO系统-标准C的I/O和文件I/O的更多相关文章

  1. 文件IO和标准IO

    2015.2.26 星期四,阴天 今天的内容主要是文件IO man 手册的分册: man -f open 查看那些分册中有openman 1 -- 普通的命令程序man 2 -- 系统调用man 3 ...

  2. 彻底明白Java的IO系统

    java学习:彻底明白Java的IO系统 文章来源:互联网 一. Input和Output1. stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源.在Java的IO中,所有 ...

  3. Java的IO系统

     Java IO系统     "对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务."     由于存在大量不同的设计方案,所以该任务的困难性是很容易证明的.其中最大的 ...

  4. Java——IO系统概览

    前言 对程序语言的设计者来说,创建一个好的输入/输出(IO)系统是一项艰难的任务.这艰难主要来自于要涵盖I/O的所有可能性.不仅存在各种I/O源端和想要与之通信的接收端(源端/接收端:文件.控制台和网 ...

  5. 文件IO和标准IO的区别【转】

    一.先来了解下什么是文件I/O和标准I/O: 文件I/O:文件I/O称之为不带缓存的IO(unbuffered I/O).不带缓存指的是每个read,write都调用内核中的一个系统调用.也就是一般所 ...

  6. 系统调用IO和标准IO

    目录 1. 系统调用IO(无缓冲IO) 系统调用 常用系统调用IO函数 open close read write lseek ioctl 2. 标准IO(带缓冲IO) 概述 缓冲与冲洗 常用标准IO ...

  7. IO系统-基本知识

    注:本文档主要整理了Linux下IO系统的基本知识,是整理的网易云课堂的学习笔记,老师讲得很不错,链接如下:Linux IO系统 1.Linux操作系统的基本构成 内核:操作系统的核心,负责管理系统的 ...

  8. 文件IO与标准IO的区别

    文件IO与标准IO的区别 文件I/O就是操作系统封装了一系列函数接口供应用程序使用,通过这些接口可以实现对文件的读写操作,文件I/O是采用系统直接调用的方式,因此当使用这些接口对文件进行操作时,就会立 ...

  9. 从零开始山寨Caffe·拾贰:IO系统(四)

    消费者 回忆:生产者提供产品的接口 在第捌章,IO系统(二)中,生产者DataReader提供了外部消费接口: class DataReader { public: ......... Blockin ...

随机推荐

  1. Vue中的computed和watch

    看了网上很多资料,对vue的computed讲解自己看的都不是很清晰,今天忙里抽闲,和同事们又闲聊起来,对computed这个属性才有了一个稍微比较清晰的认识,下面的文章有一部分是转自: https: ...

  2. url查找参数

    function GetUrlParam(paraName) { var url = document.location.toString(); var arrObj = url.split(&quo ...

  3. 【矩阵乘法优化dp】[Codeforces 621E] Wet Shark and Blocks

    http://codeforces.com/problemset/problem/621/E E. Wet Shark and Blocks time limit per test 2 seconds ...

  4. 2019 ICPC 陕西西安邀请赛 D. Miku and Generals

    传送门:https://nanti.jisuanke.com/t/39271 题意: 给你n个人,每个人有一个权值 a_i ​,(a_i​是可以被100整除的))现在需要你将n个人分成两组,有m个关系 ...

  5. Consul etcd ZooKeeper euerka 对比

    这里就平时经常用到的服务发现的产品进行下特性的对比,首先看下结论: Feature Consul zookeeper etcd euerka 服务健康检查 服务状态,内存,硬盘等 (弱)长连接,kee ...

  6. unsupported jsonb version number 123

    PostgreSQL  jsonb 入库时遇到   unsupported jsonb version number 123 变通方法 insert into  htclanedata (laneda ...

  7. lambda应用

    def test(a, b, func): result = func(a, b) print(result) test(10, 15, lambda x, y: x + y) #coding=utf ...

  8. JS事件之自建函数bind()与兼容性问题解决

    JavaScript事件绑定常用方法 对象.事件 = 函数; 它只能同时为一个对象的一个事件绑定一个响应函数 不能绑定多个,如果有多个,后面的会覆盖前面的 addEventListener() 此方法 ...

  9. Jquery为动态添加的元素添加事件

    $("tbody").on("click","button", function() { var text = $(this).parent ...

  10. 利用Redis实现集群或开发环境下SnowFlake自动配置机器号

    前言: SnowFlake 雪花ID 算法是推特公司推出的著名分布式ID生成算法.利用预先分配好的机器ID,工作区ID,机器时间可以生成全局唯一的随时间趋势递增的Long类型ID.长度在17-19位. ...