Linux C 文件IO
文件IO
2021-05-31 12:46:14 星期一
文件描述符:是有限资源
| 文件描述符 | POSIX名称 | 用途 | stdio流 |
|---|---|---|---|
0 |
STDIN_FILENO |
标准输入 | stdin |
1 |
STDOUT_FILENO |
标准输出 | stdout |
2 |
STDERR_FILENO |
标准错误 | stderr |
基础IO
open
#include <fcntl.h>
int open(const char *path, int oflag, mode_t mode);
path文件的路径和名称flag文件的打开模式,组合使用时需要使用位运算或- 基本模式
只读 只写 读写 O_RDONLYO_WRONLYO_RDWR000102
- 附加模式(只列常用)
O_APPEND:总是在文件末尾添加数据O_EXCL:配合O_CREAT标志- 表明如果文件存在则不会打开文件,并使open调用失败,否则能够创建并打开文件。这样确保了调用
open()的进程即为创建文件的进程. - 同时不允许path是符号链接
- 表明如果文件存在则不会打开文件,并使open调用失败,否则能够创建并打开文件。这样确保了调用
O_CREAT:没有文件存在时会创建文件,需要mode参数指明文件权限,一共9个O_TRUNC:如果文件存在且为普通文件且该进程对改文件有写权限,则清空文件内容
- 基本模式
modeS_IRUSR:文件所有者有读权限S_IWUSR:文件所有者有写权限S_IXUSR:文件所有者有执行权限S_IRGRP:同组用户有读权限S_IWGRP:同组用户有写权限S_IXGRP:同组用户有执行权限S_IROTH:其他用户有读权限S_IWOTH:其他用户有写权限S_IXOTH:其他用户有执行权限
- 返回文件描述符
fd或者-1
错误
creat
旧版使用,新版都用open进行创建文件
read
将open返回的fd文件描述符中读取bytes字节的数据到buf中,返回实际读取的字节数,不成功返回-1
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t bytes);
- 当
read普通文件:调用成功返回实际读取的字节数,遇到文件EOF时返回0,出现错误返回-1。 - 当
read读取终端,遇到\n即返回
注意:read系统调用是逐字节读取的,所以无法遵守C语言中的字符串的规则。比如C语言中字符串以\0(0x0)作为结束,但是read认为这里的字节值是0x0并继续读下去.所以使用read读数据时,通常的方式是:每次读取数据,再将的实际读取到的size处设置成C语言认可的字符串结束符,即buffer[size] = '\0';
#define MAX_READ 16
char buffer[MAX_READ + 1];
ssize_t size;
size = read(fd, buffer, MAX_READ);
if (size == -1)
exit(0);
buffer[size] = '\0';
close(fd);
一个例子
该文件从终端读取一行(因为read读终端时以\n作为结束)字符并打印出来,同时打印每一个字符
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define MAX_READ 16
int main(int argc, char **argv)
{
char buffer[MAX_READ + 1];
memset(buffer, 0x23, sizeof(buffer)); // fill with #
buffer[MAX_READ] = '\0';
ssize_t numRead, i;
numRead = read(STDIN_FILENO, buffer, MAX_READ);
if (numRead == -1)
perror("read");
// buffer[numRead] = '\0';
printf("the input data was:%s\n", buffer);
for (i = 0; buffer[i] != '\0' && i < MAX_READ; i++)
printf("%ld->%x\n", i, buffer[i]);
return 0;
}
$ ./4.4
abcd
the input data was:abcd
############
0->61
1->62
2->63
3->64
4->a
5->23
6->23
...
16->0
由此可见read只是以二进制的形式照搬数据,并不对数据进行处理,因此,对数据的处理留给了程序员
write
将bytes字节的buf数据写到open返回的fd文件描述符所指的文件中,返回实际写的字节数,不成功返回-1,写入已打开的文件。调用成功并不代表已经写入磁盘,可能先进入缓存(这样减少磁盘活动量、加快write调用)。
#include <unistd.h>
ssize_t write(int fd, void *buf, size_t bytes);
close
#include <unistd.h>
int close (int fd);
close函数也有错误处理,编程时也应该错误检查。
lseek
内核打开的文件时会记录文件偏移量,第一字节的偏移量为0,文件打开时,会将偏移量设置为0
十分重要:有时候读文件读不出来,可能就是因为文件偏移量在文件末尾处,这时候需要重置
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd文件描述符offset表示偏移量- 正值为正向移动,向继续往下读的方向
wherece表示文件读写指针从哪里开始计数SEEK_SET表示起始位置SEEK_CUR表示当前位置SEEK_END表示末尾位置的后一个字节(这里直接写数据的话是恰好和文件连接)
- 返回新的文件偏移量或
-1(执行失败)
文件空洞
从文件结尾后到新写入的数据间的空间,他不占用磁盘空间,直到写入了数据。这时文件的名义的大小可能比磁盘存储的总量大。具体的在14节
ls -l file 查看文件逻辑大小
du -c file 查看文件实际占用的存储块多少
od -c file 查看文件存储的内容
unlink删除
只是删除path到文件的一个链接,其文件对于的i-node减1,为0时,改文件才从磁盘删除。
#include <unistd.h>
int unlink(const char *path);
iotcl
文件和目录
目录是另一种文件,只是内容是包含的文件信息和目录信息。
链接
每一个文件对应一个inode,文件的链接数对应inode中的链接数,记录着这个文件的链接数值,即指向该inode的文件数,文件和inode是多对一的关系。本质上rm指令调用系统调用unlink函数,将这个文件的inode的链接数-1,为0时才真正删除
- 硬链接
- 相链接的文件总是同步
- 软链接
- 理解为Windows的快捷方式
$ touch a.txt
$ echo "hello" > a.txt
$ ls -li
total 4
2104443 -rw-rw-r-- 1 dwr dwr 6 Apr 10 22:20 a.txt
# inode编号 文件权限 用户 组用户 不知道 创建月 日 时 文件名
$ ln a.txt a.txt.bak # 建立硬链接
$ ls -li
total 8
2104443 -rw-rw-r-- 2 dwr dwr 6 Apr 10 22:20 a.txt
2104443 -rw-rw-r-- 2 dwr dwr 6 Apr 10 22:20 a.txt.bak
$ ln -s a.txt a.txt.s # 建立软链接
$ ls -li
total 8
2104443 -rw-rw-r-- 2 dwr dwr 6 Apr 10 22:20 a.txt
2104443 -rw-rw-r-- 2 dwr dwr 6 Apr 10 22:20 a.txt.bak
2099642 lrwxrwxrwx 1 dwr dwr 5 Apr 10 22:25 a.txt.s -> a.txt
#include <unistd.h>
int link(const char *__from, const char *__to);
int symlink(const char *__from, const char *__to);
错误打印
perror
<errno.h>
根据设置的errno值打印对应的错误信息,打印规则是先打印s中用户定义的错误输出,在打印系统调用错误的输出提示。一定要在系统调用之后紧跟打印,否则会被覆盖
void perror(const char *s);
strerror
将错误代码转换为字符串错误信息。
char *strerror(int errno);
原子IO
fcntl
#include <fcntl.h>
int fcntl(int __fd, int __cmd, ...)
文件IO缓冲
这里是Unix系统编程手册第13章内容,不全待完善
read()和write()系统调用在操作磁盘文件时不会直接发起磁盘访问,而是仅仅在用户空间缓冲区与内核缓冲区高速缓存(kernel buffer cache)之间复制数据。write()在后续某个时刻,内核会将其缓冲区中的数据写入(刷新至)磁盘。
Linux 内核对缓冲区高速缓存的大小没有固定上限。内核会分配尽可能多的缓冲区高速缓存页,而仅受限于两个因素;可用的物理内存总量,以及出于其他目的对物理内存的需求(例如,需要将正在运行进程的文本和数据页保留在物理内存中)。若可用内存不足,则内核会将
解释一下书中对IO系统调用的实验:
- 总用时=CPU用时+磁盘读写用时
- CPU用时=用户CPU用时(用户模式下执行的代码)+系统CPU用时(内核模式(系统调用和数据在用户和内核模式下传输)下执行的代码)
stdio的缓冲
C语言中IO函数可以理解为系统IO调用+数据缓冲,免于编写者自己处理对数据的缓冲
int setvbuf(FILE *stream, char *buf, int modes, size_t n)
控制stdio库函数的缓冲形式,需要最先调用,之后的stdio操作才有效
stream- 表示配置缓冲的文件流
buf- 不为空则使用size大小作为缓冲区(这个buf空间应该是堆内存上,避免函数调用和返回对栈进行修改)
- 为空则自动分配(根据mode选择是否分配)size大小空间
modes_IONBF:not,不缓冲,每一次调用stdio函数都立即调用系统调用_IOLBF:line,行缓冲,遇到换行符或缓冲区满则调用系统调用,指向终端设备的流默认使用该模式_IOFBF:file,全缓冲,指向磁盘的流默认使用该模式
- 出错返回非0,成功返回0
Linux C 文件IO的更多相关文章
- linux中文件IO
一. linux常用文件IO接口 1.1. 文件描述符 1.1.1. 文件描述符的本质是一个数字,这个数字本质上是进程表中文件描述符表的一个表项,进程通过文件描述符作为index去索引查表得到文件表指 ...
- 漫谈linux之文件IO篇(SSD写性能和机械硬盘差不多,读是4到10倍)
前同事的文章,觉得写得很清晰,收藏了. http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 开发中,有几个关系到性能的东西,技术 ...
- linux下 文件IO 相关
linux下操作文件或设备,需要一个文件描述符 file descriptor,fd 来引用.fd是一个非负整数,实际上是一个索引值,指向文件的记录表,对文件的操作都需要fd.默认的几个:标准输入流 ...
- 【Linux】文件IO --- sync、fsync、fdatesync
在使用write函数向文件中写入数据的时候,并不是在调用了函数以后就直接把数据写入磁盘:操作系统在内核中设置了一块专门的缓冲区,数据会先被写入到内核的缓冲区中,等到缓冲区满了或者系统需要重新利用缓冲区 ...
- imx6用文件io操作gpio
具体请参考: http://blog.csdn.net/u014213012/article/details/53140781 这里要注意的是: 要让linux支持文件io方式操作gpio,首先驱动必 ...
- 转 漫谈linux文件IO
在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...
- 漫谈linux文件IO
在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...
- Linux中的IO复用接口简介(文件监视?)
I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...
- Linux下用文件IO的方式操作GPIO(/sys/class/gpio)(转)
通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction ...
随机推荐
- Day14_79_IO+Properties联合应用
IO+Properties联合应用 - dbinfo文件中可以存放<key=value> - 像dbinfo这样的文件我们叫做配置文件,配置文件的作用是使程序更加灵活 - 一般在程序中可变 ...
- Day10_53_Collections.synchronizedList() 将Arraylist集合转换为线程安全的集合
将Arraylist集合转换为线程安全的集合 import java.util.ArrayList; import java.util.Collections; import java.util.Li ...
- 四两拨千斤——你不知道的VScode编码TypeScript的技巧
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://blog.bitsrc 如果你体验过JAVA这种强类型语言带来的便利,包括其丰富的 ...
- SpringCloud之配置中心(config)的使用Git+数据库实现
SpringCloud微服务实战系列教程 -------------------------目录------------------------------ 一.配置中心应用(Git) 二.配置中心的 ...
- hdu4604 不错的子序列问题
题意: 给你一个栈,里面有n个数,和一个双头队列(空的),每次从栈里拿出一个数据,有三种选择,可以选择丢弃这个数字,也可以放到队头或者队尾,最后问你这个队列你面的最长连续非下降序列的长度. ...
- drbd虚拟机宕机恢复方法
问题现象 云南计算节点YN-ec-compute-19因系统盘损坏宕机且操作系统无法恢复,其上本地虚拟机无法疏散且无法迁移 拟采用drbd备份的数据对compute19上的虚拟机进行恢复 恢复方法 1 ...
- 【vue-09】axios
[vue-09]axios 文档:Axios中文文档 官网 为什么要使用axios 功能特点: 支持发送ajax异步 支持在NodeJs中发送ajax请求. 支持Promise 支持拦截器请求和响应 ...
- 微信小程序支付功能完整流程
支付流程 整个支付流程分为四个步骤: 获取令牌token 创建订单 预支付,获取支付参数对象pay 发起微信支付 收尾工作.跳转到订单页面,删除购物车中已购买的商品 请求方式:POST 整个支付过程中 ...
- 老J的技术分享之总结
老J做IT这块有二十多个年头了,算是中国IT的见证者与参与者.那个时候刚开始接触和了解时,对于他的一些建议,我不是很乐于去接受,因为我觉得他的那一套技术体系不是很适合如今的情况,当时间久了后发现,他对 ...
- base64stego 还不懂base64的隐写,详解15行代码带你领略
网上写了好多关于xctf MISC新手篇的base64Stego隐写的教程,但大都不太清楚,基本上都是讲了一段隐写原理,直接上代码了.但是代码是这道题的关键,代码讲了如何解码这个隐写的完整流程,这次我 ...