Linux系统标准IO函数

标准IO函数

使用底层系统调用open/read/write等对文件进行操作效率非常低,原因主要有两个:

  • 使用系统调用会影响系统的性能。与函数调用相比,系统调用的开销较大,因为在执行系统调用时,Linux必须从运行用户代码切换到内核代码,然后再返回用户代码。而减少这种开销的一个好方法是,在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作。
  • 硬件会限制对底层系统调用一次所能读写的数据块。

为了个设备和磁盘文件提供更高层的接口,Linux发行版提供一个标准函数库。标准IO库及其头文件stdio.h为底层IO系统调用提供了一个通用的接口。这个库现在已经成了ANSI标准C的一部分,库函数主要包括fopen/fread/fwrite/printf/scanf/fprintf/fscanf等库函数。

fopen函数

#include<stdio.h>
FILE *fopen(const char *filename, const char *mode);

fopen库函数打开由filename参数指定的文件,并把它与一个文件流关联起来。fopen成功时返回一个非空的FILE*指针,失败时返回NULL值。

参数说明:

  • filename:指定打开的文件名
  • mode:指定打开文件的方式,可能是一下字符串中的一种:
字符串 说明
“r"或"rb” 以只读方式打开
“w"或"wb” 以写方式打开,并把文件原有内容删除
“a"或"ab” 以写方式打开,新内容追加在文件尾
"r+"或"rb+“或"r+b” 以读写方式打开
"w+"或"wb+“或"w+b” 以读写方式打开,并文件原有内容删除
"a+"或"ab+“或"a+b” 以读写方式打开,新内容最佳在文件尾

字母b表示文件是一个二进制文件,但是Linux并不区分文本文件和二进制文件,而是把所有文件都看作为二进制文件。

Linux系统可用的文件流数量和文件描述符一样都是有限制的,实际的限制由头文件stdio.h中定义的POPEN_MAX定义,它的值至少为8,Linux系统通常为16。

fread函数

#include<stdio.h>

size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

fread函数用于从一个文件流里读取数据。返回值是成功读到数据缓冲区里的记录个数(而不是字节数)。

参数说明:

  • ptr:指定数据缓冲区
  • size:指定每个元素的大小,以字节为单位
  • nitems:指定要读取元素的个数,每个元素的大小为size字节
  • stream:指定要读取的文件流指针

fwrite函数

#include<stdio.h>

size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);

fwrite函数用于从指定的数据缓冲区里取出数据记录,并把它们写到输入流中。返回值是成功写入的记录个数。

参数说明:

  • ptr:指定数据缓冲区
  • size:指定每个元素的大小,以字节为单位
  • nitems:指定要写入元素的个数,每个元素的大小为size字节
  • stream:指定要写入的文件流指针

fclose函数

#include<stdio.h>

int fclose(FILE *stream);

fclose函数用于关闭一个文件流,并使所有尚未写出的数据都写出。

因为stdio库会对数据进行缓冲,所以使用fclose是很重要的。如果程序需要确保数据已经全部写出,就应该调用fclose函数。当程序正常结束时,会自动对所有还打开的文件流调用fclose函数。

fflush函数

#include<stdio.h>

int fflush(FILE *stream);

fflush函数把文件流里的所有未写出的数据立即写出。调用fclose函数隐含执行了一次flush操作,所以不必在调用fclose之前调用fflush。

fseek函数

#include<stdio.h>

int fseek(FILE *stream, long int offset, int whence);

fseek函数在文件流里为下一次读写操作指定位置。返回值是一个整数:0表示成功,-1表示失败并设置errno指出错误。

参数说明:

  • stream:指定文件流指针
  • offset:指定偏移量
  • whence:指定偏移量的用法,可选下列值之一:
说明
SEEK_SET offset是一个绝对位置
SEEK_CUR offset是相当于当前位置的一个相对位置
SEEK_END offset是相对于文件尾的一个相对位置

fgetc、getc和getchar函数

#include<stdio.h>

int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar();

fgetc函数从文件流里取出下一个字节并把它作为一个字符返回。当它到达文件尾或出现错误时返回EOF。

getc函数作用同fgetc一样。

getchar函数的作用相当于getc(stdin),从标准输入里读取下一个字符。

fputc、putc和putchar函数

#include<stdio.h>

int fputs(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

fputc函数把一个字符写到输出文件流中。返回值是写入的值,失败返回EOF。

putc函数作用同fputc函数.

putchar函数相当于putc(c,stdout),将字符c写到标准输出文件流中。

fgets和gets函数

#include<stdio.h>

char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);

fgets函数把读到的字符写到s指向的字符串里,直到遇到换行符或者已经读取n-1个字符或者遇到文件尾。它会把遇到的换行符也传递到接收字符串里,再加上一个表示结尾的空字符尾0。

fgets成功完成时返回一个指向字符串s的指针,如果文件流已经到达文件尾,fgets会设置这个文件流的EOF标识并返回一个空指针。如果出现读错误,fgets返回一个空指针并设置errno。

gets函数从标准输入读取数据并丢弃遇到的换行符,并在接收字符串尾部加上一个null字节。警告:gets对传输字符的个数并没有限制,所以它可能会溢出自己的传输缓冲区,所以应该避免使用gets函数。

许多安全问题都可以追溯到程序中使用了可能造成各种缓冲区溢出的函数,gets就是一个这样的函数。

printf、fprintf和sprintf函数

#include<stdio.h>

int printf(const char *format, ...);
int sprintf(const *s, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);

printf函数将输出送到标准输出流。
sprintf函数把输出加上一个结尾空字符送到字符串s中。
fprintf函数把输出输送到指定的文件流中。

format为输出格式类型,通常有以下几种常用的转换控制符:

转换控制符 说明
%d,%i 以十进制格式输出一个整数
%o,%x 以八进制或十六进制格式输出一个整数
%c 输出一个字符
%s 输出一个字符串
%f 输出一个单精度浮点数
%e 以科学计数法输出一个双精度浮点数
%g 以通用格式输出一个双精度浮点数

scanf、fscanf和sscanf函数

#include<stdio.h>

int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s,const char *format,. ...);

scanf系列函数使用一个格式字符串来控制输入数据的转化。
scanf函数从标准输入流中读入数据。fscanf函数从指定的文件流中读入数据。sscanf函数则从指定的字符串中读入数据。

format为输入格式类型,通常有以下几种常用的转换控制符:

转换控制符 说明
%d 读取一个十进制整数
%o,%x 读取一个八进制或十六进制的整数
%c 读取一个字符
%s 读取一个字符串
%f 读取一个单精度浮点数
%e 读取一个科学计数法表示的双精度浮点数
%g 读取一个通用格式表示双精度浮点数
%[] 读取一个字符集合
%% 读取一个%字符

值得一提的是,使用%c空字符从输入中读取一个字符,它不会跳过起始的空白字符。

关于scanf的安全性问题,由于scanf系列函数可以接受任意的键盘输入,如果输入的长度超出了应用给定的缓冲区,就会覆盖其他数据区,造成缓冲区溢出,而溢出的数据可能覆盖其他内存空间的数据,造成程序崩溃。


参考文献:《Linux程序设计(第4版)》

猜你喜欢

转载自blog.csdn.net/qq_38600065/article/details/104956117