Linux标准I/O基础及函数介绍

1.流和FILE对象

对于ASCII字符集,一个字符用一个字节表示;对于国际字符集,一个字符可用多个字节表示。

  • 标准I/O文件流可用于单字节或多字节字符集。
  • 流的定向决定了所读、写的字符是单字节还是多字节的。
  • 当对一个未定向的流使用单(多)字节I/O函数,则将该流的定向设置为字节(宽)定向。
  • 只有两个函数可以改变流的定向:
    • freopen函数清除一个流的定向。
    • fwide函数设置流的定向。

2.流的定向

#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);
// 返回值:若流是宽定向的则返回正值,若流是字节定向的则返回负值,若流是未定向的则返回0

根据mode参数的不同值,fwide函数执行不同的工作:

mode说明
负值使流是字节定向
正值使流是宽定向
0不设置流的定向,但返回该流定向的值

fwide无出错返回,在调用前应该先清空errno,返回时检查errno的值来判断是否出错。

3.标准输入、标准输出和标准错误

标准I/O为每个进程自动开启三个流:标准输入标准输出标准错误。这三个标准I/O流通过预定义文件指针stdinstdoutstderr加以引用。

4.缓冲

标准I/O提供了三种类型的缓冲:

  • 全缓冲:填满标准I/O缓冲区后才进行实际I/O操作。
  • 行缓冲:在遇到换行符时执行实际I/O操作。
  • 无缓冲:不对字符进行缓冲存储。

stdinstdout默认是行缓冲,而stderr默认是无缓冲的。

使用setbufsetvbuf函数可自行设置流的缓冲类型,函数原型如下:

#include <stdio.h>
void setbuf(FILE *fp, char* buf);
int setbuf(FILE *fp, char* buf, int mode, size_t size);
// 返回值:若成功则返回0,若出错则返回非0值

在调用setbuf函数时,若buf是NULL,则关闭该流的缓冲;若buf不为NULL则必须指向一个长度为BUFSIZ的缓冲区,此时该流是全缓冲的。

setvbuf函数可以通过mode参数精确地指定所需的缓冲类型:

mode说明
_IOFBF全缓冲,buf和size可指定缓冲区及其长度
_IOLBF行缓冲,buf和size可指定缓冲区及其长度
_IONBF无缓冲,忽略buf和size参数

当mode为_IOFBF或_IOLBF时,若buf是NULL,则标准I/O库将自动地为该流分配BUFSIZ长度的缓冲区。

如果不想等待缓冲,立即执行I/O操作,可以调用fflush函数冲洗一个流。

#include <stdio.h>
int fflush(FILE *fp);
// 返回值:若成功则返回0,若出错则返回EOF

若fp是NULL,则此函数将导致所有输出流被冲洗。

5.流的打开和关闭

#include <stdio.h>
FILE* fopen(const char *pathname, const char *type);
FILE* freopen(const char *pathname, const char *type, FILE *fp);
FILE* fdopen(int filedes, const char *type);
// 三个函数的返回值:若成功则返回文件指针,若出错则返回NULL
  • fopen打开一个指定的文件。
  • freopen重定向一个流到指定的文件。
  • fdopen把现有的文件描述符与标准I/O流结合,通常用于管道和网络通信通道函数返回的描述符。

打开标准I/O流的type参数有以下形式:

type说明
r或rb只读
w或wb把文件截短至0长,或创建并只写
a或ab添写,或创建并只写
r+或r+b或rb+读写
w+或w+b或wb+把文件截短至0长,或为读写而打开
a+或a+b或ab+为在文件尾读写而打开或创建

可见,文件以只写打开时会被截短,但是fdopen例外。因为该描述符已经被打开,所以fdopen为写而打开并不截短文件。

#include <stdio.h>
int fclose(FILE *fp);
// 返回值:若成功则返回0,若出错则返回EOF

fclose函数关闭一个打开的流。在文件被关闭之前,

  • 缓冲区中的输出数据会被冲洗。
  • 缓冲区中的输入数据会被丢弃。
  • 缓冲区会被释放。

当一个进程正常终止时,所有带未写缓冲数据的标准I/O流都会被冲洗,所有打开的标准I/O流都会被关闭。

如果需要把标准I/O流转换成文件描述符以配合文件I/O函数,则可以调用以下函数:

#include <stdio.h>
int fileno(FILE *fp);
// 返回值:与该流相关联的文件描述符

6.读和写流

程序通常需要从标准I/O流读数据,以下函数提供读取单个字符的方式:

#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
// 三个函数的返回值:若成功则返回下一个字符,若已到达文件结尾或出错则返回EOF

这三个函数在返回下一个字符时,会将unsigned char类型转换为int类型,这样就可以用负值作为已出错或已到达文件结尾的指示值。

不管是出错还是到达文件结尾,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferrorfeof函数。

#include <stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
// 两个函数的返回值:若条件为真则返回非0值,否则返回0
void clearerr(FILE *fp);

FILE对象中存在两个标志:出错标志文件结束标志clearerr函数可以清除这两个标志。

从流中读取数据后,可以调用ungetc将字符再压送回流中。

#include <stdio.h>
int ungetc(int c, FILE *fp);
// 返回值:若成功则返回c,若出错则返回EOF

压送回到流中的字符以后还可从流中读出,读出的顺序与压送回的顺序相反。

下面两个函数提供每次输入一行的功能:

#include <stdio.h>
char* fgets(char *buf, int n, FILE *fp);
char* gets(char *buf);
  • gets函数从标准输入读,而fgets从指定的流读。
  • gets无法指定缓冲区长度,容易造成缓冲区溢出。
  • fgets必须指定缓冲区长度n。
  • fgets读到下一个换行符为止,但不超过n-1个字符。
  • fgets返回的行始终以null字符结尾。

当需要读写的不是字符而是二进制数据时,可使用以下函数:

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp);
// 两个函数的返回值:读或写的对象数
  • fread会调用malloc申请堆内存来缓存读入的数据。
  • 这两个函数的常见用法有:读写二进制数组读写结构体
  • ptr是指向数组元素或结构体的指针,size是数组元素或结构体的大小,nobj表示读入的个数

对于fread,若返回值小于nobj,则需要调用ferror或feof判断是否出错或到达文件尾段。
对于fwrite,若返回值小于nobj,则出错。

7.定位流

与文件I/O类似,标准I/O同样提供了操作文件偏移量的方法。

#include <stdio.h>
long ftell(FIle *fp);
// 返回值:若成功则返回当前文件位置指示,若出错则返回-1L
int fseek(FILE *fp, long offset, int whence);
// 返回值:若成功则返回0,若出错则返回非0值
void rewind(FILE *fp);

这三个函数的用法与文件I/O的类似函数并无区别,ftellfseek函数假定偏移量可以存放在长整型中。

ftellofseeko函数则用off_t数据类型代替了长整型,可以使文件偏移量不必一定使用长整型。以下为函数原型:

#include <stdio.h>
off_t ftello(FILE *fp);
// 返回值:若成功则返回当前文件位置指示,若出错则返回-1
int fseeko(FILE *fp, off_t offset, int whence);
// 返回值:若成功则返回0,若出错则返回非0值

与以上函数相同,fgetposfsetpos函数也可以设置文件偏移量:

#include <stdio.h>
int fgetpos(FILE *fp, fpos_t *pos);
int fsetpos(FILE *fp, const fpos_t *pos);
// 两个函数返回值:若成功则返回0,若出错则返回非0值

fgetpos将文件偏移量的当前值存入由pos指向的对象中。在以后调用fsetpos时,可以使用此值将流重新定位至该位置。

8.格式化I/O

程序经常需要定制输出信息,为了避免过多手动拼接字符串,标准I/O提供了格式化输出函数,使用格式说明来预定其他参数如何编写。

#include <stdarg.h>
#include <stdio.h>
int vprintf(const char *format, va_list arg);
int vfprintf(FILE *fp, const char *format, va_list arg);
// 两个函数返回值:若成功则返回输出字符数,若出错则返回负值
int vsprintf(char *buf, const char *format, va_list arg);
int vsnprintf(char *buf, size_t n, const char *format, va_list arg);
// 两个函数返回值:若成功则返回存入数组的字符数,若出错则返回负值

同样,标准I/O也提供了格式化输入函数,用于限制和校验输入的参数:

#include <stdarg.h>
#include <stdio.h>
int vscanf(const char *format, va_list arg);
int vfscanf(FILE *fp, const char *format, va_list arg);
int vsscanf(const char *buf, const char *format, va_list arg);
// 三个函数返回值:指定的输入项数,若输入出错或在任一变换前已到达文件结尾则返回EOF
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值