C语言文件基本操作

什么是文件

与普通文件载体不同,文件是以硬盘为载体存储在计算机上的信息集合,文件可以是文本文档、图片、程序等等。文件通常具有点+三个字母的文件扩展名,用于指示文件类型(例如,图片文件常常以KPEG格式保存并且文件扩展名为.jpg)。

将数据放入文件中,相比代码程序中堆栈上的数据,其优点在于可以随时做到需要时添加、舍弃时删除,数据可以持久化。

文件分类:

文件一般讲两种:程序文件和数据文件;

程序文件:

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

数据文件:

包括程序运行时所读写的数据。本篇所涉及的就是数据文件。

文件的使用

文件的操作一般分三步:1.打开文件;2.读/写;3.关闭文件;

 

文件指针

想要对文件进行操作,“文件指针”就是一个关键桥梁(亦名:文件类型指针);

底层原理:每个被使用的文件,都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如:文件名、文件状态、文件位置等),这些信息被保存到一个结构体中,系统为其声明为FILE,每当打开一个文件的时候,系统就会根据情况自动创建一个FILE结构的变量,并且通过FILE*的指针来维护这个结构。

文件指针的使用:

   FILE* pf;

定义一个文件指针变量pf,它可以指向某个文件的文件信息区,通过其即可访问到该文件。

 

 

 

 

文件的打开和关闭

        在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指
针和文件的关系。

fopen() —— 打开文件;
FILE * fopen ( const char * filename, const char * mode );
fclose() —— 关闭文件;
int fclose ( FILE * stream );

文件的使用方式:

按常用序:

文件的顺序读写:

以上结合起来实例:

#include<stdio.h>
#include<string.h>
#include<errno.h>
 
int main()
{
    FILE* pf= fopen("test.txt", "w+");
    if (pf == NULL)
    {
        printf("%s\n", strerror(errno));
        return;
    }
    //输入一个字符
    fputc('a', pf);
    //用完关闭文件
    fclose(pf);
    pf = NULL;
 
    return 0;
}

如图示:在源文件所在目录下,原本没有test.txt文件,是w+创建了这个新的文件,并写入一个字符a 

1.写入一个字符:

//写文件    
    fputc('a', pf);

2.读取一个字符:

//读取一个字符
    int ch = fgetc(pf);
    if (ch != EOF)
    {
        printf("%c\n", ch);
    }

3.连续每次读取一个字符:

//文件中有abcdefg
    int ch = fgetc(pf);
    printf("%c\n", ch);    //a
    ch = fgetc(pf);
    printf("%c\n", ch);    //b
    ch = fgetc(pf);
    printf("%c\n", ch);    //c
    ch = fgetc(pf);
    printf("%c\n", ch);    //d

4.覆盖并写入一行数据:

fputs("hello world", pf);

注意:这里fputs函数虽然是整行写入,但会覆盖掉原始数据

5.读取指定长度的数据:

//定一一个数组
    char arr[10] = { 0 };
    fgets(arr, 5, pf);    //将所读取的数据放入arr中
    printf("%s\n", arr);

6.将结构体信息写入文件中:

这里的结构体信息就是格式化的,那么就需要fprintf()函数了

#include<stdio.h>
 
typedef struct S
{
    char name[10];
    int age;
 
}Peo;
int main()
{
    FILE* pf = fopen("test.txt", "w");
 
    if (pf != NULL)
    {
        Peo p = { "zhangsan", 18 };
        fprintf(pf, "%s %d\n", p.name, p.age);
 
        fclose(pf);
        pf = NULL;
    }
 
    return 0;
}

7.读取文件信息到结构体变量中:

#include<stdio.h>
 
typedef struct S
{
    char name[10];
    int age;
 
}Peo;
int main()
{
    FILE* pf = fopen("test.txt", "r");
 
    if (pf != NULL)
    {
        Peo p = { 0 };
 
        fscanf(pf, "%s %d", p.name, &p.age);
 
        printf("%s %d", p.name, p.age);
 
        fclose(pf);
        pf = NULL;
    }
 
    return 0;
}

8.二进制写入文件:

  • size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
#include<stdio.h>
#include<string.h>
#include<errno.h>
 
typedef struct S
{
    char name[10];
    int age;
 
}Peo;
int main()
{
    FILE* pf = fopen("test.txt", "wb+");
 
    if (pf != NULL)
    {
        Peo p = { "lisi", 19};
 
        fwrite(&p, sizeof(Peo), 1, pf);
 
        fclose(pf);
        pf = NULL;
    }
 
    return 0;
}

9.读取二进制文件信息:

  • size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

#include<stdio.h>
 
typedef struct S
{
    char name[10];
    int age;
 
}Peo;
int main()
{
    FILE* pf = fopen("test.txt", "rb+");
 
    if (pf != NULL)
    {
        Peo p = { 0 };
 
        fread(&p, sizeof(Peo), 1, pf);
 
        printf("%s %d\n", p.name, p.age);
 
        fclose(pf);
        pf = NULL;
    }
 
    return 0;
}

 

 

10.sscanf()函数、sprintf()函数:

这两个函数虽然和文件操作关系不大,但是容易与文件操作函数混淆;

  • sscanf()函数:
  • int sscanf( const char *buffer, const char *format [, argument ] ... );
  • 将一个字符串转化为格式化数据;
#include<stdio.h>
 
typedef struct S
{
    char name[10];
    int age;
 
}Peo;
int main()
{
    //定义一个字符串
    char buffer[] = { "zhansan 19" };
    //定义一个结构但不赋值
    Peo p = { 0 };
 
    sscanf(buffer, "%s %d", p.name, &p.age);
 
    return 0;
}

  • sprintf()函数:
  • int sprintf( char *buffer, const char *format [, argument] ... );

  • 将一个格式化数据转化为字符串;

#include<stdio.h>
 
typedef struct S
{
    char name[10];
    int age;
 
}Peo;
int main()
{    
    //定义一个结构
    Peo p = { "zhangsan",19};
    //定义一个字符串
    char buffer[50] = { 0 };
 
    sprintf(buffer, "%s %d\n", p.name, p.age);
 
    return 0;
}

文件读取结束判定

feof()函数:

该函数被许多人错误用来判断文件是否读取结束,其实它的作用是判断文件读取结束的原因;

文件读取结束有两种情况:1.读取过程中出现异常; 2.读取到文件末尾;

要找出文件读取是哪个原因,就分为以下情况:

文本文件:

如果用 fgetc() 读取,要判断 feof() 的返回值是否为EOF;
如果用 fgets() 读取,要判断 feof() 的返回值是否为NULL(0);

二进制文件:

都是使用 fread() 读取,要判断其返回值与指定读取个数的大小,如果小于实际要读的个数,就说明发生读取异常,如果等于实际要读的个数,就说明是因读取成功而结束;

对于读取异常的判断,我们考虑判断 ferror() 函数的返回值:

若ferrror()为真——异常读取而结束;
若feof()为真——正常读取到尾而结束;

文本文件的判断:

#include<stdio.h>
#include<string.h>
#include<errno.h>
 
int main()
{
    FILE* pf = fopen("test.txt", "r");
 
    if (pf == NULL)
    {
        perror("fopen is failed !");
        return;
    }
    int c = 0;
    //由于要检查EOF——EOF本质是0——所以是int
    while (c = fgetc(pf) != EOF)
    {
        putchar(c);
    }
    //直到while不执行了—读取结束了—判断是什么原因结束的
    if (ferror(pf))
    {
        printf("读取中出现错误\n");
    }
    else if (feof(pf))
    {
        printf("读取到文件尾\n");
    }
 
    fclose(pf);
    pf = NULL;
 
    return 0;
}

 

转载:https://blog.csdn.net/m0_65190367/article/details/126682477

posted @ 2022-10-15 16:03  kuailest  阅读(124)  评论(0编辑  收藏  举报