C进阶-语言文件操作

本章重点:

什么是文件

文件名

文件类型

文件缓冲区

文件指针

文件的打开和关闭文件的顺序读写文件的随机读写文件结束的判定

1. 什么是文件

磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件

1.1 程序文件

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

1.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

1.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。文件名包含3部分:文件路径+文件名主干+文件后缀

例如: c:\code\test.txt

为了方便起见,文件标识常被称为文件名。

2. 文件的打开和关闭

2.1 文件指针

缓冲文件系统中,关键的概念是"文件类型指针",简称"文件指针"。

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE. 例如,VS2008编译环境提供的 stdio.h头文件中有以下的文件类型申明:

cpp 复制代码
struct _iobuf {
    char *_ptr;
    int _cnt;
    char *_base;
    int _flag;
    int _file;
    int _charbuf;
    int _bufsiz;
    char *_tmpfname;
};
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关

心细节。

一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

下面我们可以创建一个FILE*的指针变量:

FILE* pf;//文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文 件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

2.2 文件的打开与关闭

cpp 复制代码
int main()
{
    //相对路径
    //绝对路径
    ///Users/fan/Documents/c_study/c_test26/data.txt

    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件


    //关闭文件
    fclose(pf);
    pf = NULL;


    return 0;
}

3. 文件的顺序读写

3.1 顺序读写函数介绍

cpp 复制代码
int main()
{
    //相对路径
    //绝对路径
    ///Users/fan/Documents/c_study/c_test26/data.txt

    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","w");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件
    //写文件
    // fputc('a',pf);
    // fputc('b',pf);
    // fputc('c',pf);
    int i = 0;
    for (i = 0; i < 26; i++)
    {
        fputc('a'+i,pf);
    }


    //关闭文件
    fclose(pf);
    pf = NULL;


    return 0;
}
cpp 复制代码
int main()
{
    //相对路径
    //绝对路径
    ///Users/fan/Documents/c_study/c_test26/data.txt

    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件
    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


    //写文件
    // fputc('a',pf);
    // fputc('b',pf);
    // fputc('c',pf);
    // int i = 0;
    // for (i = 0; i < 26; i++)
    // {
    //     fputc('a'+i,pf);
    // }


    //关闭文件
    fclose(pf);
    pf = NULL;


    return 0;
}
cpp 复制代码
int main()
{
    //相对路径
    //绝对路径
    ///Users/fan/Documents/c_study/c_test26/data.txt

    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件
    // 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


    //写文件
    // fputc('a',pf);
    // fputc('b',pf);
    // fputc('c',pf);
    // int i = 0;
    // for (i = 0; i < 26; i++)
    // {
    //     fputc('a'+i,pf);
    // }

    // fputs("hello fan\n",pf);
    // fputs("hello fanfan\n",pf);

    //读文件 - 读一行
    char arr[10] = {0};
    fgets(arr,15,pf);
    printf("%s\n",arr);
    fgets(arr,15,pf);
    printf("%s\n",arr);


    //关闭文件
    fclose(pf);
    pf = NULL;


    return 0;
}
cpp 复制代码
struct S
{
    int a;
    float s;
};

int main()
{
    //相对路径
    //绝对路径
    ///Users/fan/Documents/c_study/c_test26/data.txt

    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //写文件
    //struct S s = {100,3.14f};
    //fprintf(pf,"%d %f",s.a,s.s);
    struct S s = {0};
    fscanf(pf,"%d %f",&(s.a),&(s.s));

    printf("%d %f",s.a,s.s);


    //关闭文件
    fclose(pf);
    pf = NULL;


    return 0;
}
cpp 复制代码
struct S
{
    int a;
    float s;
    char str[10];
};

int main()
{

    struct S s = {99, 6.18f, "bit"};
    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","wb");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }
    //写文件
    fwrite(&s,sizeof(struct S),1,pf);

    //关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}
cpp 复制代码
int main()
{

    struct S s = {0};
    //打开文件
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","rb");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }
    
    //读文件
    fread(&s,sizeof(struct S),1,pf);
    printf("%d %f %s\n",s.a,s.s,s.str);

    //关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

4. 文件的随机读写

4.1 fseek

根据文件指针的位置和偏移量来定位文件指针。

int fseek ( FILE * stream , long int offset , int origin );

cpp 复制代码
int main()
{
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件
    //定位文件指针到f
    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

    fseek(pf,-3,SEEK_END);
    ch = fgetc(pf);
    printf("%c\n",ch);


    //关闭文件
    fclose(pf);
    pf = NULL;



    return 0;
}

4.2 ftell

返回文件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

cpp 复制代码
int main()
{
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件
    //定位文件指针到f
    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

    // fseek(pf,-3,SEEK_END);
    // ch = fgetc(pf);
    // printf("%c\n",ch);
    int pos = ftell(pf);
    printf("%d\n",pos); //4


    //关闭文件
    fclose(pf);
    pf = NULL;



    return 0;
}

4.3 rewind

让文件指针的位置回到文件的起始位置

void rewind ( FILE * stream );

cpp 复制代码
int main()
{
    FILE* pf = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    //读文件
    //定位文件指针到f
    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

    // fseek(pf,-3,SEEK_END);
    // ch = fgetc(pf);
    // printf("%c\n",ch);
    // int pos = ftell(pf);
    // printf("%d\n",pos); //4

    rewind(pf);  //回到起始位置

    ch = fgetc(pf);
    printf("%c\n",ch); //a

    //关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

5. 文本文件和二进制文件

6. 文件读取结束的判断

6.1 被错误使用的feof

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。

而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)

例如:

fgetc判断是否为EOF.

fgets判断返回值是否为NULL.

2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如:

fread判断返回值是否小于实际要读的个数。

cpp 复制代码
int main(void)
{
    int c; // 注意:int,非char,要求处理EOF
    FILE *fp = fopen("test.txt", "r");
    if (!fp)
    {
        perror("File opening failed");
        return EXIT_FAILURE;
    }
    // fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
    {
        putchar(c);
    }
    // 判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

//拷贝文件
//拷贝data.txt文件,产生一个新文件data1.txt

int main()
{
    FILE* pfRead = fopen("/Users/fan/Documents/c_study/c_test26/data.txt","r");
    if (pfRead == NULL)
    {
        perror("open file for read");
        return 1;

    }

    FILE* pfWrite = fopen("/Users/fan/Documents/c_study/c_test26/data2.txt","w");
    if (pfWrite == NULL)
    {
        perror("open file for write");
        fclose(pfRead);
        pfRead = NULL;
        return 1;
    }


    //读写文件
    int ch = 0;
    while((ch = fgetc(pfRead)) != EOF)
    {
        fputc(ch,pfWrite);
    }


    //关闭文件
    fclose(pfRead);
    pfRead = NULL;

    fclose(pfWrite);
    pfWrite = NULL;


    return 0;
}

7. 文件缓冲区

相关推荐
isyangli_blog8 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008118 小时前
FastAPI APIRouter
开发语言·python
Benszen8 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆8 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木8 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充9 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~9 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6169 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草9 小时前
反射、Tomcat执行
java·开发语言
雪的季节10 小时前
企业级 Qt 全功能项目
开发语言·数据库·qt