文件IO,fileIO 也可以说是系统调用IO,以文件描述符(file descriptor)为核心。
1. 文件描述符(fd)
一个进程同时打开2个文件的情况,如下图:
有几个问题:
- 这个文件描述符的数组的大小是多少呢?进程最大打开文件的大小;命令
ulimit -n
- 这个数组存放在哪里?每个进程空间都会有这么个进程
-
一个进程可以同时打开一个文件两次吗?
-
可以。如下图fd4和fd5都打开了同一个文件,所以这个file的结构体中可能存在一个count的计数器,只有当没有fd正在使用该文件的时候,这个file结构体空间才会被free。
-
两个进程可以同时打开一个文件吗?
可以。可能是这样的,不确定
另外,关于文件描述符的几个注意点:
- STDIN_FILE,STDOUT_FIELNO,STDERR_FILENO 三个常量包含在
中; - OPEN_MAX 最大打开文件个数
2. 文件IO操作:
read write open close lseek 等,标准IO函数都是基于这5个函数实现的。
3. fileIO和stdIO的区别
- 响应速度快:FILEIO
-
吞吐量大:STDIO
- 如何加快程序的速度?
- 标准IO和文件IO,能否混用?
- 别混用,读取位置游标不一致咋办?
- 可以使用fileno()/fdopen()函数转换。
- 例子 ab.c
4. IO的效率问题
效率问题最重要的是bufsize的选择。写一个例子mycp.c
# BUFSIZE 循环次数 real user sys
1 373293056 662.84 31.40 628.40
2 186646528 301.75 13.89 287.24
4 93323264 148.39 6.61 141.39
8 46661632 87.81 3.61 83.72
16 23330816 51.50 2.08 48.71
32 11665408 26.29 1.02 24.66
64 5832704 13.28 0.53 12.20
128 2916352 6.38 0.25 5.77
256 1458176 9.05 0.11 2.73
512 729088 2.10 0.06 1.65
1024 364544 1.37 0.02 1.01
2048 182272 1.18 0.01 0.84
4096 91136 0.92 0.00 0.52
8192 45568 0.96 0.00 0.60
16384 22784 1.21 0.00 0.56
32768 11392 1.18 0.00 0.73
65536 5696 0.92 0.00 0.52
131072 2848 1.03 0.00 0.56
262144 1424 1.27 0.00 0.72
524288 712 1.29 0.00 0.78
1048576 356 2.65 0.00 1.07
2097152 178 3.37 0.00 1.22
4194304 89 4.72 0.00 0.92
8388608 45 18.91 0.00 0.65
发现后面越来越快,是有问题的,因为都保存在文件系统缓存里了。
看APUE书中介绍有几个点:
- 这个复制的文件,大小相同但是不同内容的文件;
- 这个文件要大于内存大小;?
- BUFSIZE 达到16MB的时候,会出现段错误;?
- 当BUFSIZE与文件系统块大小相同的时候,速度最快。
=注意点:
使用time命令后得到的是三个时间:
real 0m0.000s = user+sys+一点点
user 0m0.000s
sys 0m0.000s
sys:在内核或者系统调用上消耗的时间
user:用户进程中消耗的时间
real:为啥多一点点?有调度等待的时间,中断等等
用户真正在意的是real时间,而程序员在意的是user+sys时间,调度的时间程序员也无法左右。
常规用的time嵌在bash内,可以单独安装GNU的time包。time -f "%e %U %S"
5. 文件共享
题目:删除一个文件的第十行。
- 方案1:一个进程对一个文件同时打开两次
- 同时对这一个文件打开两个文件描述符,一个只读一个读写。
- 一个fd操作只读第11行首之后的内容;
- 一个fd将刚才读到的内容写到10行开头。
- 依次循环,直到文件尾部。
- 使用truncate截断文件多余内容。
使用getline获取一行:deleteline10-getline.c