分类: LINUX
2012-01-03 12:16:18
++++++APUE读书笔记-05标准输入输出库(4)++++++
7、行输入输出
================================================
下面两个函数提供行输入功能:
#include
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
返回:如果成功返回buf,如果失败或者到达文件结尾返回NULL。
两者以行的方式操作流。fgets需要指定缓存的大小,然后读取一行,读取的结果包含new line和一个null结束。如果行长超过了n,那么就读取到n,最后也包含一个null字符(需要仔细调查???),反正fgets最多读取n-1个字符。gets已经逐渐被淘汰了,因为没有指定缓存大小,不安全,另外它并不把newline存放到buffer中。
下面是一个例子:
/*程序功能:
使用fgets读取文件的一行,并且打印出来。
*/
#include
int main(int argc, char *argv[])
{
char chars[256];
FILE *f = fopen("./test","r");
while(!feof(f))
{
fgets(chars,256,f);//注意回车也都读取了
printf("%s",chars,ftell(f));
//printf("%s:%ld",chars,ftell(f));
}
fclose(f);
return 0;
}
下面两个函数提供行输出功能:
#include
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
两者返回:如果成功返回非负,否则返回EOF。
fputs会把一个null结束的字符串写到一个指定的stream中。结尾的null字节并不会被写入。需要注意的是,这个函数并不一定是一次一行的输出,因为输出的字符串并不需要把newline作为最后的非空字符。一般来说,最后一个非空字符会是newline字符,但是这不是必须的。
puts函数会把null字符串写入到标准输出,但是不会写入空字符。另外,puts还会把一个newline字符输出到标准输出。
puts函数是安全的,而不像相应的gets。然而,我们也要避免使用它,否则还要记住它要在输出的最后追加一个newline字符。如果我们始终使用fgets和fputs,我们会知道我们怎样处理每一行最后的一个newline字符。
参考:
8、标准输入输出的效率
================================================
这一节,将使用标准输入输出和直接使用系统调用进行输入输出的时间进行了对比,主要是对:char的std I/O,line的std I/O,系统调用设置最优缓存的I/O,以及系统调用没有设置缓存的I/O 进行了对比,对比的表格如下:
使用标准输入输出库的时间
+------------------------------------------------------------------------------------------------------------------------------+
| Function | User CPU (seconds) | System CPU (seconds) | Clock time (seconds) | Bytes of program text |
|-----------------------------------+--------------------+----------------------+----------------------+-----------------------|
| best time from Figure 3.5 | 0.01 | 0.18 | 6.67 | |
|-----------------------------------+--------------------+----------------------+----------------------+-----------------------|
| fgets, fputs | 2.59 | 0.19 | 7.15 | 139 |
|-----------------------------------+--------------------+----------------------+----------------------+-----------------------|
| getc, putc | 10.84 | 0.27 | 12.07 | 120 |
|-----------------------------------+--------------------+----------------------+----------------------+-----------------------|
| fgetc, fputc | 10.44 | 0.27 | 11.42 | 120 |
|-----------------------------------+--------------------+----------------------+----------------------+-----------------------|
| single byte time from Figure 3.5 | 124.89 | 161.65 | 288.64 | |
+------------------------------------------------------------------------------------------------------------------------------+
这里,第1行的"best time from Figure3.5"对应原书中的相应图形,其实就是之前第3章8节中的I/O效率对比表格中,直接使用系统调用,传入最优缓存大小所用的时间(使得系统调用次数最少从而消耗时间最少)。我们通过操作一个98.5MB大小的文件(大约300万行),来显示这些数据,通过上表我们发现:
直接使用库函数,并不比最优缓存的系统调用I/O差很多。使用库函数,我们不用考虑系统最优缓存了,有时候只是考虑buffer大小就行了,这比系统调用考虑最优缓存方便多了。如果line的std I/O使用char的std I/O实现的话,其消耗的时间要比char的std I/O要大,但是由于line的std I/O是用高效率的memccopy实现的,所以快。
使用char的std I/O比没有缓存的系统调用I/O要快,尽管循环次数差不多,而且char的还额外增加了一点sys的循环,但是一次系统调用的代价,比一次函数调用的代价大很多,所以,char的std I/O比纯粹没有缓存系统调用的I/O代价要小。
使用std I/O需要增加一些system time用来拷贝。一般重要的程序,I/O应该占用user time更多。
参考: