一、一切皆文件
Linux/UNIX操作系统把所有的服务、设备、协议都抽象成文件的形式,提供了一套统一而简单的文件IO的系统调用,简称系统的文件IO
也就是说在UNIX\Linux中任何对象都可以被当做是某种特殊的文件,都可以像访问文件一样,访问这些对象
文件分类:
普通文件 - 包括纯文本文件、二进制文件、各种压缩文件
目录文件 d 必须有执行权限才能进入目录
块设备文件 b 保存大块数据的硬件设备,例如磁盘
字符设备文件 c 操作字符相关的设备 例如键盘、鼠标等
socket文件(套接字文件) s 通常用于网络通信
管道文件 p 用于进程间通信
链接文件 l 类似Windows的快捷方式
二、文件相关的系统调用
int open(const char *pathname, int flags);
功能:打开文件
pathname:文件的路径
flags:打开文件的方式
O_RDONLY 只读 //文件必须存在
O_WRONLY 只写 //文件必须存在
O_RDWR 读写 //文件必须存在
O_APPEND 追加
O_CREAT 文件不存在则创建
O_EXCL 配合O_CREAT,如果文件存在则失败
O_TRUNC 文件如果存在,则清空打开
返回值:文件描述符fd,类似于FILE*,代表了一个打开的文件(>=0),负数表示失败
int open(const char *pathname, int flags, mode_t mode);
功能:创建文件
flags:O_CREAT
mode:
S_IRWXU 00700 拥有者 读写执行权限
S_IRUSR 00400 读权限
S_IWUSR 00200 写权限
S_IXUSR 00100 执行权限
S_IRWXG 00070 同组用户 读写执行权限
S_IRGRP 00040 读
S_IWGRP 00020 写
S_IXGRP 00010 执行
S_IRWXO 00007 其它用户 读写执行权限
S_IROTH 00004 读
S_IWOTH 00002 写
S_IXOTH 00001 执行
注意:可给宏名 也可以给 权限掩码 (0xxx) 八进制
int creat(const char *pathname, mode_t mode);
功能:创建文件
mode:同上
练习:测试fopen的各种打开方式与open的flags的对应情况
strace ./a.out
ssize_t write(int fd, const void *buf, size_t count);
功能:把内存中的数据写入的文件中
fd:文件描述符 open creat的返回值
buf:待写入的内存的首地址
count:要写入的字节数
返回值:成功写入的字节数
ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据到内存中
fd:文件描述符 open creat的返回值
buf:存储读取出来的数据的内存首地址
count:要读取的字节数
返回值:成功读取的字节数
分别使用标准IO和系统IO写入一百万个整数到文件,测试谁的时间更短?为什么?
结论:在同等数据的写入下,使用标准IO要比直接使用系统IO更快
原因:标准IO有缓冲区机制,在执行fwrite写文件时,数据不是直接调用系统IO写入磁盘,而是先存放在内存的缓冲区中,
直到缓冲区满后才会调用一次系统IO全部写入到磁盘,因此对系统IO的调用次数、用户态内核态的转换次数都大大降低
系统IO是没有缓冲区机制,每写一次数据就要进入一次内核态,浪费了大量时间进行内核态与用户态的切换,因此耗时增加
解决:如果给系统IO也加上缓冲区机制,那么它的速度要比标准IO更快
三、随机读写:
每个打开的文件都有一个记录读写位置的指针,也称文件位置指针,对文件的读写时该指针会自动往后移动,因此顺序读写时无需操作
当需要去文件的任意位置进行读写时,才需要调整该指针的位置
标准IO:
int fseek(FILE *stream, long offset, int whence);
返回值:成功0 失败-1
系统IO:
off_t lseek(int fd, off_t offset, int whence);
返回值:成功返回调整后位置指针的位置 失败-1
四、系统IO中的文本文件的读写:
在系统IO中没有类似fprintf\fscanf函数,因此没有直接对文本文件读写的操作 //注意是文本文件
但是可以通过把数据转换成字符串进行间接的文本文件读写
写文本文件
任意类型数据对象 sprintf 转换成字符串 write写入
读文本文件
按字符串格式读取到内存 sscanf 解析到任意类型数据中