Linux系统C语言读写文件总结 (二)

来源:互联网 发布:odysseus windows 编辑:程序博客网 时间:2024/05/09 22:40

1. 概述

这里所说的是标准I/O库。以标准二字限定,是因为接下来介绍的I/O函数由ISO C标准说明并在诸多操作系统上都进行了实现,包括UNIX like OS, Linux, Mac, Windows等。标准I/O库处理了很多细节,例如缓冲区分配,以优化长度执行I/O等。这些处理使得用户不必担心如何使用正确的块长度,从而大大提高了开发效率。


标准I/O库实际上就是在我在上一片博客(Linux系统C语言读写文件总结 (一))中提到的基本I/O操作函数(read,write等)的一个封装。标准I/O函数操作对应的是于文件相关的流(用文件指针FILE *进行表示),而不是文件描述符(fd)。一个FILE结构中包括了实际操作文件的文件描述符,指向用于该流缓冲区的指针,缓冲区的长度,当前在缓冲区中的字符数以及出错标志等等。


此外流的定向分为面向单字节的和多字节字符集。freopen函数可以用来清除流的定向,fwide函数可以用来设置流的定向。


2. 标准输入,标准输出和标准出错

有几个特殊的流,对应于标准输入,标准输出和标准出错。他们的文件指针分别是stdin, stdout和stderr,并被定义在头文件<stdio.h>中。到这儿了就可以回想下这三个特殊文件对应的文件描述符。


3. 缓冲

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

(1)全缓冲。

(2)行缓冲。

(3)不带缓冲。


4. 打开和关闭流

打开流,成功返回文件指针,否则返回NULL

    #include<stdio.h>    FILE *fopen(const char *restrict pathname, const char *restrict type);    FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp);    FILE *fdopen(int filedes, const char *type);
type指定对该I/O流的读写方式,ISO C规定该参数有15种不同的值,如下

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

注:这里r+, w+, a+都可以对文件进行写。区别在于以r+方式打开,文件位置指向文件开头;以w+方式打开,会将原文件长度截短为0;以a+方式打开会将文件位置指向文件结尾处且将结尾处作为文件位置的开始,fseek函数也不能将文件位置指向开头处。所以这也就解释了我的疑问:为什么会有r+的存在。

关闭流,成功返回0,否则返回EOF

    #include<stdio.h>    int fclose(FILE *fp);

5. 读和写流(非格式化)

三种不同类型的非格式化I/O:

(1)每次一个字符的I/O。

输入函数

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

getc可以实现为宏(更快),而fgetc则只能是函数;getchar等价于getc(stdin)。

其对应的输出函数为

    #include<stdio.h>    int putc(int c, FILE *fp);    int fputc(int c, FILE *fp);    int putchar(int c);
成功则返回c,否则返回EOF。

putc可以实现为宏(更快),而fputc则只能是函数;putchar等价于putc(c, stdout)。


(2)每次一行的I/O。

输入函数

    #include<stdio.h>    char *fgets(char *restrict buf, int n, FILE *restrict fp);    char *gets(char *buf);

成功则返回buf,若已达到文件结尾或出错则返回NULL。

fgets从指定流读,而gets从标准输入读。fgets必须指定缓冲区的长度n,此函数一直读到下一个换行符为止,但是不超过n-1(缓冲区以null结尾)个字符,读入的字符被送入缓冲区。

gets这是一个不推荐使用的函数。因为用户不能指定缓冲区的长度,可能造成缓冲区溢出。

其对应的输出函数为

    #include<stdio.h>    char *fputs(const char *restrict str, FILE *restrict fp);    char *puts(const char *str);

成功则返回非负值,否则返回EOF。


尽量避免使用gets和puts。使用fgets和fputs时需要记住在每行终止处必须处理换行符。


(3)直接I/O(二进制I/O)。

    #include<stdio.h>    size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);    size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
返回值:读或写的对象数。

例子:

a. 写一个数组

    float data[10];    if(write(&data[2], sizeof(float), 4, fp) != 4)        err_sys("fwrite error");

b. 写一个结构体

    struct{        short cout;        long total;        char name[NAMESIZE];    }item;    if(fwrite(&item, sizeof(item), 1, fp) != fp)        err_sys("fwrite error");

6. 格式化I/O

格式化输出

    #include<stdio.h>    int printf(const char *restrict format, ...);    int fprintf(FILE *restrict fp, const char *restrict format, ...);//若成功则返回输出的字符数,若输出出错则返回负值    int sprintf(FILE *restrict buf, const char *restrict format, ...);    int snprintf(FILE *restrict buf, size_t n, const char *restrict format, ...);//若成功则返回存入数组的字符数,如编码出错则返回负值

其中的format的描述形式如:%[flags][fldwidth][precision][lenmodifier]convtype

flags选项如下表

标志说明-在字段内左对齐输出+总是显示带符号转换的符号(空格)如果第一个字符不是符号,则在其前面加上一个空格#指定另外一种转换形式(例如,对于十六进制格式,加0x前缀)0添加前导0(而非空格)进行填充

fldwidth说明转换的最小字段宽度,如果转换得到的字符较少,则用空格填充它。字段宽度是一个非负十进制数,或是一个星号(*)。

precision说明整型转换后最少输出数字位数,浮点数转换后小数点后的最少位数,字符串转换后的最大字符数。精度时一个句号(.),后接一个可选的非负十进制整数或一个星号(*)。

转换类型选项如下表

转换类型说明d, i有符号十进制o无符号八进制u无符号十进制x, X无符号十六进制f, Fdouble精度浮点数e, E指数格式的double精度浮点数g, G解释为f, F或e, E,取决于被转换的值a, A十六进制指数格式的double精度浮点数c字符(若带长度修饰符l,则为宽字符)s字符串(若带长度修饰符l,则为宽字符)p指向void的指针n将到目为止,所写的字符数写入到指针所指向的无符号整型中%%字符C宽字符(XSI扩展,等效于lc)S宽字符串(XSI扩展,等效于ls)

格式化输入

    #include<stdio.h>    int scanf(const char *restrict format, ...);    int fscanf(FILE *restrict fp, const char *restrict format, ...);    int sscanf(FILE *restrict buf, const char *restrict format, ...);    //若成功则返回指定的输入项数,如输入出错或在任意变换前已经到达文件结尾则返回EOF

format格式转换说明如下:%[*][fldwidth][lenmodifier]convtype

除转换说明和空白字符外,格式字符串中的其他字符必须与输入匹配。若有一个字符不匹配,则停止后续处理,不再读输入的其他部分。

*用于抑制转换。

fldwidth说明最大宽度(即最大字符数)。

lenmodifier说明要用转换结果初始化的参数大小。

转换类型选项如下表。与print族有些类似,但是也有所差别。一个差别是,存储在无符号类型中的结果可在输入时带上符号。例如,-1可被转换成4,294,967,295赋予无符号整型变量。

转换类型说明d有符号十进制,基数为10i有符号十进制,基数由输入格式决定o无符号八进制(输入可选地有符号)u无符号十进制,基数为10(输入可选地有符号)x无符号十六进制(输入可选地有符号)a, A, e, E, f, F, g, G浮点数c字符(若带长度修饰符l,则为宽字符)s字符串(若带长度修饰符l,则为宽字符)[匹配列出的字符序列,以 ] 终止[^匹配列出字符序列以外的所有字符,以 ] 终止p指向void的指针n将到目为止读取的字符数写入到指针所指向的无符号整型中%%字符C宽字符(XSI扩展,等效于lc)S宽字符串(XSI扩展,等效于ls)


7. 定位流

    #include<stdio.h>    long ftell(FILE *fp);                    //成功则返回当前文件位置指示,出错返回-1L    int fseek(FILE *fp, long offset, in whence);                    //成功返回0,出错返回非0值    void rewind(FILE *fp);                    //将一个流设置到文件的起始位置
    #include<stdio.h>    off_t ftello(FILE *fp);                    //成功返回当前文件位置指示,出错则返回-1    int fseeko(FILE *fp, off_t offset, int whence);                    //成功则返回0,出错则返回非0值
除了offset的类型时off_t而非long外,ftello函数和ftell相同,fseeko和fseek相同
    #include<stdio.h>    int fgetpos(FILE *restrict fp, fpos_t *restrict pos);    int fsetpos(FILE *fp, const fpos_t *pos);                    //成功则返回0,出错则返回非0值
这两个函数时ISO C标准引入的。如果程序要移植到非UNIX系统,则可以使用该函数。其中fgetpos将文件位置指示器的的当前值存入到由pos指向的对象中。在以后调用fsetpos时,可以使用此值将流重新定位至该位置。
0 0
原创粉丝点击