美文网首页
C语言基础05:文件IO

C语言基础05:文件IO

作者: 陈有余 | 来源:发表于2018-04-04 17:53 被阅读15次

    一、文件的概念

    C语言的文件是指用来存储数据的一种存储设备。存储在文件中的数据并不会随着计算机的关闭而消失。文件通常是存储在硬盘上的。

    二、文件的访问

    (一)打开文件

    使用函数:fopen()

    使用方法:

    char *path = "H:\\AndroidNDK\\cworkspace\\files\\friends.txt";
    FILE *fp = fopen(path, "r");
    

    函数的第一个变元是一个字符串指针,他是要处理的外部文件的名称。
    函数的第二个变元是也是一个字符串,称为文件模式。它指定对文件进行什么处理。这里介绍常用的三种模式:

    文件模式

    如果我们需要处理的是一个二进制的文件,比如一个音频、视频或者图片时,那么文件模式为:"wb"、"ab"、"rb"。b 是 binary(二进制)的简写。

    如果成功调用fopen()函数,它会返回一个FILE *类型的指针(该指针称为文件指针或者流指针),通过该指针可以引用文件,使用其他库函数执行输入输出的操作。如果文件因为某种原因但不开,会返回一个空指针(NULL)。

    一次能打开的文件数由<stdio.h>中定义的常量FOPEN_MAX确定。C语言标准规定,FOPEN_MAX的值至少为8,包括stdin、stdout和stderr。因此我们至少一次可以处理5个文件,但是这个数字常常大很多,例如256。

    打开文件更安全的可选备用函数是:fopen_s():

    errno_t fopen_s(_Outptr_result_maybenull_ FILE ** _File, _In_z_ const char * _Filename, _In_z_ const char * _Mode);
    
    • 第一个变量需要我们传入一个文件指针的地址
    • 第二个变量需要我们传入文件名(带路径或不带路径)
    • 第三个变量需要我们传入文件模式(w、a、r)

    1.写入模式(w)

    FILE *fp;
    char *fileName = "H:\\AndroidNDK\\cworkspace\\hello.txt";
    errno_t err = fopen_s(&fp, fileName, "w");
    if (err != 0){
        printf("%s\n","文件打开失败");
        return;
    }
    printf("%s","请输入需要写入的字符(以#号结束):");
    char str_append;
    while ((str_append = getchar()) != '#'){
        fputc(str_append, fp);
    }
    fclose(fp);
    

    对于第二个参数 fileName 可以写全路径

    //如果包含这个文件的目录不存在,fopen_s()函数不会创建目录,也不会创建文件,而是失败。
    //如果目录存在,但是该目录下没有找到文件,就在该位置上创建文件。
    char *fileName = "H:\\AndroidNDK\\cworkspace\\hello.txt";
    

    也可以不带路径,直接写文件名称:

    //不带路径的话,该文件会保存到当前项目所在的目录下
    char *fileName = "hello.txt";
    

    注:如果fopen_s()函数调用失败,就返回非0整数,pfile设置为NULL。
    使用fopen_s()函数对文件进行写入操作时,是不允许并发访问的。

    2.追加模式(a)
    如果要在已有的文本文件中添加数据,而不是覆盖数据,可以指定模式为“a”,它是操作的追加模式。将文件指针放在前一次写入的数据的末尾。如果文件不存在,就会创建新文件。

    fopen_s(&fp, fileName, "a");
    

    3.读取模式(r)
    如果要读取文件,可以使用如下代码:

    fopen_s(&fp, fileName, "r");
    

    如果是读取模式,文件就必须存在,如果要读取的文件不存在,fopen_s()会把指针设置为NULL。

    (二)缓存文件

    打开文件后,就可以调用 setvbuf() 控制如何缓存输入操作,其函数原型如下:

    int setvbuf(FILE * restrict pfile, char * restrict buffer, int mode, size_t size);
    
    • 参数一:打开文件的文件指针
    • 参数二:用于缓存的数组,第四个参数是该数组的大小。如果把第二个参数置为NULL,就用第四个变量指定的大小分配一个缓存。一般建议把第二个变量置为NULL,这样就不用考虑缓存的创建或其生命周期了。
    • 第三个参数:指定缓存模式。其值如下:
      _IOFBF:使文件完全缓存。输入输出完全缓存时,数据块会以任意大小读写。
      _IOLBF:使操作缓存一行。输入输出缓存一行时,读写的数据用换行符来分块。
      _IONBF:使用输入输出不缓存。对于不缓存的输入输出,数据会逐个字符地传递。这是非常低效的。所以仅在需要时使用这个模式。

    一切正常时,setvbuf()返回 0 整数。示例代码:

    //对pfile指向的文件使用setvbuf()
    size_t bufsize = 1024;
    if(setvbuf(pfile, NULL, _IOFBF, bufsize))
      printf("文件缓存失败!\n");
    

    如果只是希望完全缓存输入或输出,可以调用 setbuf() ,其函数原型为:

    void setbuf(FILE * restrict pfile, char * restrict buffer);
    
    • 第一个参数:文件指针
    • 第二个参数:用作缓冲区的数组地址。可以为NULL,此时自动创建缓冲区。如果指定缓冲区,其长度必须为
      BUFSIZ 字节,BUFSIZ在 stdio.h 中定义。下面使用自己的缓冲区给pfile指针指向的文件缓存操作:
    char *buf = malloc(BUFSIZ);
    setbuf(pfile,buf);
    

    (三)重命名文件

    使用函数 rename()
    函数原型:

    int rename(const char *oldname, const char *newname);
    

    如果文件名称修改成功返回0,否则返回非零值。调用rename()函数时,文件必须关闭,否则操作会失败。
    示例代码如下:

    if (rename("H:\\cworkspace\\friends.txt", "H:\\cworkspace\\boy.txt")){
            printf("文件名修改失败\n");
        }
        else{
            printf("文件名修改成功\n");
        }
    

    (四)关闭文件

    使用函数:fclose()

    fclose(fp);
    fp=NULL;
    

    如果成功关闭文件,就返回0,否则返回EOF。

    注:EOF是一个特殊的字符,称为文件结束字符。EOF一般表示不能再从流中获取数据了
    使用完文件后最好马上关闭文件

    三、写入文本文件

    最简单的写入操作由函数 fputc 提供,它将一个字符写入文本文件。其原型如下:

    int fputc(int ch,FILE *pfile)
    

    函数fputc()将第一个变量指定的字符写入第二个变量指定的文件中。如果操作成功,就返回写入的字符,否则就返回EOF。

    注:实际上,字符不是一个一个地写入物理文件的,这样做效率太低了。字符先被写入到内存中的缓冲区,缓冲区累积到一定的数量后,就一次将它们写入文件。

    写入文件.jpg

    四、读取文本文件

    fgetc() 函数从打开的文本文件中读取一个字符,需要传入一个文件指针对象作为参数,读取的字符返回为 int 类型,示例代码如下:

    int ch = fgetc(pfile)
    

    如果读取到文件末尾,就返回 EOF。读取文件的机制与写入文件正好相反。在一次操作中将一整块字符写入缓冲区,接着一次将一个字符传送给程序,直到缓冲区为空,此时再读取另一块。

    如果需要再次读取文本内容,可以调用 rewind() 函数把文件指针变量指定的文件定位到开头。

    rewind(pfile)
    

    pfile必须是已经打开的文件。

    五、在文本文件中读写字符串

    (一)读取字符串

    函数 fgets()

    char *fgets(char * restrict str, int nchars, FILE * restrict pfile);
    

    该函数会一直从文件中读取字符串,直到读到了'\n'字符或读入 nchars-1 个字符为止。如果读到换行符会保留在字符串中。字符'\0'会附加到字符串的末尾。如果没有错误,fgets()就会返回str指针,否则返回NULL。读取EOF会返回NULL。

    (二)写入字符串

    函数 fputs()

    int *fputs(char * restrict str, FILE * restrict pfile);
    

    第一个参数是要写入文件的字符串指针,第二个变量是文件指针。

    fputs("hello world\n",pfile);
    

    如果发生错误,fputs()函数返回EOF,如果正常就返回正整数。

    六、二进制文件的输入输出

    (一)二进制文件与文本文件的区别

    1.二进制文件不需要转换数据,也不需要格式字符串控制输入输出;
    2.文本模式下具有特殊意义的字符,如'\n'和‘\0’,在二进制模式下就没有意义了。

    (二)二进制模式的优点

    二进制模式的优点是没有数据转换,也没有精度的损失。而文本模式因为有格式化过程,有数据转换和精度损失。另外,二进制模式比文本模式的速度快。两种模式的比较如下图:

    二进制模式与文本模式的比较

    (三)以二进制模式打开文件

    要指定二进制模式,只需要在基本打开模式说明符后附加 b

    二进制文件操作的模式字符串
    续表

    (四)写入二进制文件

    使用函数:fwrite()
    函数原型:

    fwrite()函数原型
    • 第一个参数是要写入的数组的地址(任何类型的数组都可以)
    • 第二个参数是数组元素的字节数(sizeof(数组类型))
    • 第三个参数是数组元素的个数
    • 第四个参数是文件流的指针

    函数返回值:
    函数fwrite()将实际写入的数据项个数返回为一个整数。如果出现写入错误,禁止写入所有数据,这个整数就小于nitems。如果size或nitems是0,就不给文件写入任何数据。

    void main(){
        char *read_path = "H:\\AndroidNDK\\cworkspace\\files\\liuyan.png";
        char *write_path = "H:\\AndroidNDK\\cworkspace\\files\\liuyan_new.png";
        //读的文件
        FILE *read_fp = fopen(read_path, "rb");
        //写的文件
        FILE *write_fp = fopen(write_path, "wb");
    
        //复制
        int buff[50];//缓冲区域
        int len = 0;//每次读到的数据长度
        while ((len = fread(buff, sizeof(int), 50, read_fp)) != 0){
            fwrite(buff, sizeof(int), len, write_fp);
        }
        //关闭流
        fclose(read_fp);
            read_fp = NULL;
        fclose(write_fp);
            write_fp= NULL;
        getchar();
    }
    

    (五)读取二进制文件

    使用函数:fread()
    函数原型:

    fread()函数原型
    • pdata是要读取的数组的地址
    • size是每个数据项的字节数
    • nitems是要读取的数据项个数
    • pfile是文件指针

    函数的返回值:返回读取的个数。

    关于文件IO的知识就给大家介绍到这里


    我的在行一点,欢迎大家扫码提问:


    在行一点

    相关文章

      网友评论

          本文标题:C语言基础05:文件IO

          本文链接:https://www.haomeiwen.com/subject/bwnocftx.html