文件

基础

        c程序自动打开3个文件:标准输入,标准输出与标准错误输出。

常用函数

        为stdlib.h中定义的。

fopen()

        打开文件,第一个参数为文件的绝对路径,第二个参数为打开模式。如下:

        r只读不能写,文件还必须存在。如果文件不存在,返回的FILE*型指针为NULL。

        w可写不可读文件,如果文件不存在,就新建一个;如果文件存在,就清空文件内容之后再写入。

        a追加不可读文件,即在原本文件的结尾处再写入新的内容。如果文件不存在,就新建文件。

        r+:可读可写。但文件必须存在,将要写入的内容追加到原文件末尾。

        w+:可读可写,如果文件不存在,就新建一个;如果文件存在,就清空文件内容之后再写入。

        a+:可读可追加。不存在则新建文件。

        以w模式打开文件时,文件的内容将被删除。

fclose()

        用于关闭由fopen()打开的文件,同时根据需要刷新缓冲区。如果成功关闭返回0,否则返回EOF。

rewind()

        使程序回到文件开始的位置。

ungetc(int c,FILE* fp)

        将c指定的字符放入fp中。如果向fp中放入了一个字符,那么下次从fp中读取时就会读到该字符。如果一行里放回了多个字符,那么读取的顺序将和放回的顺序相反。如

int c;
    while((c = getchar()) != EOF){
        putchar(c);
        if(c == 'q')
            ungetc(c, stdin);
    }
        上述代码块从stdin中一次读取一个字符,将显示出来;如果该字符是q的话,就将该字符返回到stdin中。因此,这个程序的结果为:如果输入的没有q,那可以正常工作;如果有q,那么最后一直输出q。因为读取一次就将q返回一次,这使得下一次读取又是q,依此循环不止。

fflush(FILE* fp)

        将缓冲区中任何未写的数据刷新到fp指定的输出文件中。如果参数为空,则清除掉缓冲区中所有的数据。

setvbuf(FILE* fp,char* buf,int mode,size_t size)

        建立一个供标准I/O函数使用的替换缓冲区。在打开文件以后,没有进行任何操作之前可以调用该函数。fp为文件流指针,buf为缓冲区首地址,mode为缓冲区模式,size为缓冲区大小。

        如果buf为NULL,则函数会自动分配一个缓冲区。

        mode取值为:_IOLBF(行缓冲,缓冲区满时或者一个新行写入时,刷新),_IONBF(无缓冲),_IOFBF(缓冲区满时刷新)。

fseek()

        像对待数组一样对待文件,可以移动到任意字节处。

        第一个参数指向被搜索的文件的FILE指针。第二个参数为偏移量,表示从起点处开始移动的位置,正数表示前移,负数表示后退,0表示不去。第三个参数表示模式,stdio.h中定义了三种模式。SEEK_SET,文件开始位置;SEEK_CUR,文件当前位置;SEEK_END,文件结束位置。

        如果正常,则返回0;如果错误,则返回-1,比如移动的位置超出了文件范围。

feof()与ferror()

        当读取函数返回EOF时,表示已经到达了文件结尾或者读取错误。如果最近一次读取到达文件结尾,则feof()返回非零值,否则返回0;如果最近一次发生读写错误,则ferror()返回非零值,否则返回0值。

ftell()

         返回距离文件开始处的字节数目。例如可以使用它和fseek联合使用来确定文件的字符数,如下:

    fseek(f, 0, SEEK_END);
    long bs = ftell(f);

二进制IO

        前面的IO函数都是面向文本的,是用于处理字符与字符串的。那该如何保存一个数字呢?可以使用fprintf()与%f相结合的方式,但存储的时候依旧以字符串的形式进行存储的。如:
double f = 1.0/3;
fprintf(fp,"%.2f",f);
存储之后 ,f被存储成0.33。如果再次读取该值时,就会读取成0.33,无法恢复到f应有的精度。
        最精确最一致的存储方式是:程序中变量使用什么样的格式,在存储到文件中时也使用什么样的格式,例如一个double的数据就应该被存储到double大小的单元中,而不是将double的数据分解成一个个字符再进行存储。
        如果把数据存储在一个使用与程序具有相同表示方法的文件中,就称数据以二进制形式存储。在这中间并没有数字到字符的转换。而fwrite()与fread()函数提供了这种二进制的读取操作。

fwrite(void* ptr,size_t size,size_t nmemb,FILE* fp)

        ptr:在写入文件的数据块的地址。
        size:每一个数据块的大小。
        nmemb:要写入的数据块的数量
        fp:要写入的文件。
        返回值:成功写入文件的数据块的数量。一般来说,返回的就是nmemb,如果有写入错误返回值就会小于nmemb。如:
    double a[] = {1.0/3,0.43443253145};
    fwrite(a, sizeof(double)*2, 1, fp);
    double b[2];
    fread(b, sizeof(double), 2, fp);
    printf("%lf",b[1]);
        上述表示:写入的数据块大小为两个double所占的字符数,并且只写入一个数据块。

fread(void* ptr,size_t size,size_t nmemb,FILE* fp)

        各参数,返回值同上。
        上述代码中的fread()表示:每一个数据块的大小为一个double所占的字节数,要读取两个double值。

读写过程

        操作一个文件时,首先使用fopen()函数打开文件。同时建立一个缓冲区(如果能同时读写,那么就建立两个缓冲区),并创建一个包含文件和缓冲区相关数据的数据结构,返回一个指向该数据结构的指针。fopen()函数打开了一个链接到文件的流。

        该数据结构中,至少包括:文件结束指示器,复制到缓冲区的字节数,文件位置指示器(用于确定缓冲区数据在流中的位置)等。

        第二步使用某个读取函数(fscanf(),getc()和fgets()等)从缓冲区中读取所需要的数据,同时修改结构中的某些数据,如:将文件位置指示器设置成读取到的最后一个字节的下一位,更新缓冲区的字节数。

        因为所有的读取函数都使用的是同一块缓冲区,因此任何一个调用函数都在前一个函数停止的地方继续读取的。

        当读取函数已经读取了缓冲区的所有字节时,它会请求系统再将一块数据复制到缓冲区中。这样,就能保证这些函数一直读取文件末尾。当函数在读取到最后一个字节时,会将结构中的文件结束指示器设置为真,这样下一次读取的时候就返回的是EOF。

        写入函数也类似:先将数据写到缓冲区中,缓冲区已满时才将数据复制到文件中。




你可能感兴趣的:(文件)