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. cmd 如何跨驱动器移动文件夹

    如果在命令行或 cmd 批处理文件通过 move 移动文件夹的时候,移动的文件夹是跨驱动器的,那么将会显示拒绝访问 解决通过 move 移动文件夹到不同的驱动器需要通过先复制文件夹到另一个驱动器,然后 ...

  2. Qt4与Qt3的主要不同

    Qt4与Qt3的主要不同 1)QT4 中提供了大量新控件,虽然它也保持了旧的控件,并命名为Qt3XXX,但是这样的控件没准在今后的哪个QT版本中就不被支持了,所以还是换吧,控件替换的 工作是巨大的,这 ...

  3. 关于oppo和vivo这两年强势崛起的反思

    先来谈谈配置吧(小白跳过) oppo产品线 r7 67522015年05月3g2320mAh r7 p 6795 6153g4100mAh r7s 616 67522015年10月4g 3070mAh ...

  4. 017 Ceph的集群管理_3

    一.验证OSD 1.1 osd状态 运行状态有:up,in,out,down 正常状态的OSD为up且in 当OSD故障时,守护进程offline,在5分钟内,集群仍会将其标记为up和in,这是为了防 ...

  5. 【他山之石】mybatis打印sql日志 相关配置

    背景:mybatis的sql日志打印对我来说一直比较迷,哪怕看过网上很多博客后还是这样,这两天刚好又遇到了问题,要查sql不得已又来查阅,这次终于搞定了. mybatis是有提供日志功能支持的,目前支 ...

  6. 曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  7. 洛谷P5664 Emiya 家今天的饭 题解 动态规划

    首先来看一道题题: 安娜写宋词 题目背景 洛谷P5664 Emiya 家今天的饭[民间数据] 的简化版本. 题目描述 安娜准备去参加宋词大赛,她一共掌握 \(n\) 个 词牌名 ,并且她的宋词总共有 ...

  8. win10下使用mklink命令给C盘软件搬家

    在windows下,大多数软件会默认安装在C盘,即使小心翼翼地点开“自定义”->“安装路径”,然后把软件安装到其他盘,还是会有很多软件用到的数据文件被塞到C盘,虽然可以到注册表修改软件默认安装路 ...

  9. JS中常见的几种继承方法

    1.原型链继承 // 1.原型链继承 /* 缺点:所有属性被共享,而且不能传递参数 */ function Person(name,age){ this.name = name this.age = ...

  10. 【一起学源码-微服务】Feign 源码一:源码初探,通过Demo Debug Feign源码

    前言 前情回顾 上一讲深入的讲解了Ribbon的初始化过程及Ribbon与Eureka的整合代码,与Eureka整合的类就是DiscoveryEnableNIWSServerList,同时在Dynam ...