• C语言——文件


    C语言目录:

    1. 概述

    2. 数据类型

    3. 量

    4. 运算符

    5. 流程控制

    6. 函数

    7. C程序编译过程

    8. 文件

    9. 内存管理


    文件流:C语言将文件看做一个字符序列,即文件是由若干字符组成的字符流

    8.1 文件分类

    8.1.1 文本文件

    文件内容以ASCII码格式存放,一个字节存放一个ASCII码,代表一个字符 ,但占用存储空间较多

    .c 文件就是以文本文件形式存放的

    8.1.2 二进制文件

    文件内容以补码格式存放,占用存储空间少。

    数据按其内存中的存储形式原样存放

    .exe 文件就是以二进制文件形式存放

    8.1.3 示例

    #include 
    
    int main(){
        /*
         * 以文本形式存储
         * 会将每个字符先转换为对应的ASCII,
         * 然后再将ASCII码的二进制存储到计算机中
         */
        int num = 666;
        FILE *fa = fopen("ascii.txt", "w");
        fprintf(fa, "%d", num);
        fclose(fa);
    
        /*
         * 以二进制形式存储
         * 会将666的二进制直接存储到文件中
         */
        FILE *fb = fopen("bin.txt", "w");
        fwrite(&num, 4, 1, fb);
        fclose(fb);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    在这里插入图片描述

    • 记事本默认按照ASCII码逐个解码文件,由于文本文件存储的是ASCII码,所以可以正常解析
    • 记事本按照ASCII码解码文件,所以解析出来是乱码

    8.2 文件的操作

    FILE 结构体

    C语言中存放文件属性的结构体(缓冲区和文件读写状态),所有的文件操作都是通过 FILE 结构体完成的,只能通过指针访问属性

    struct _iobuf {
        char *_ptr;  //文件输入的下一个位置
        int _cnt;  //当前缓冲区的相对位置
        char *_base; //文件的起始位置)
        int _flag; //文件标志
        int _file;  //文件的有效性验证
        int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
        int _bufsiz; // 缓冲区大小
        char *_tmpfname; //临时文件名
    };
    typedef struct _iobuf FILE;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    8.2.1 打开文件

    建立程序和文件之间的通信通道,并为文件系统建立缓冲

    所在文件:stdio.h

    a. 参数及返回值

    FILE *fopen(const char *filename,const char *mode);
    //以mode的方式,打开filename命名的文件,返回一个指向该文件缓冲的FILE结构体指针
    FILE *fp = fopen("路径","w");
    
    • 1
    • 2
    • 3
    参数/返回值含义
    char *filename要打开或者创建文件的路径
    mode打开文件的方式
    FILE返回指向文件缓冲区的指针,用于操作文件

    b. 文件读写方式

    mode文件类型操作文件不存在文件存在
    r文本文件读取出错打开文件
    w文本文件写入创建新文件覆盖原文件
    a文本文件追加创建新文件原文件后追加
    r+文本文件读取/写入出错打开文件
    w+文本文件读取/写入创建新文件覆盖原文件
    a+文本文件读取/追加创建新文件原文件后追加
    rb二进制文件读取出错打开文件
    wb二进制文件写入创建新文件覆盖原文件
    ab二进制文件追加创建新文件原文件后追加
    rb+二进制文件读取/写入出错打开文件
    wb+二进制文件读取/写入创建新文件覆盖原文件
    ab+二进制文件读取/追加创建新文件原文件后追加

    8.2.2 关闭文件

    所在文件:stdio.h

    函数功能:fclose() 用来关闭之前 fopen() 打开的文件

    函数操作:让缓冲区内的数据写入文件,并释放系统提供的文件资源

    a. 参数和返回值

    int fclose(FILE *filePointer)
    
    • 1
    参数/返回值含义
    FILE *filePointe指向文件缓冲的指针
    int成功则返回0,失败则返回EOF(-1)
    int main(){
    	FILE *fp;
    	if(fopen("abc.txt","w")==NULL){
            exit(-1);//非0表示异常
        }
        fclose(fp);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    8.2.3 读写文件

    需要引入 位置指针 :打开文件,默认指向文件开头

    • 所有文件读/写,都是从 位置指针 指示的位置进行读/写

    分为

    • 顺序读写
    • 随机读写

    a. 文本文件读写

    文件尾测试函数

    文件使用特殊字符 EOF 作为文件结束标记

    int feof(FILE *stream); :判断是否读到文件结尾

    • 0表示未读到文件尾
    • 非0表示读到文件尾,此时不能读取文件

    所在文件:stdio.h

    参数:FILE *stream 是指向文件缓冲的指针

    注意:文件只有读了才会修改 位置指针 ,没有打开并读取的文件无法通过 feof(fp) 判断是否读到文件尾,一定要 先读在判断

    # include
    
    int main(){
        //打开文件
        FILE *fp = fopen("test.txt","r+");
        
        //从文件中读取内容
        char res = EOF;
        while(res = fgetc(fp) && !feof(fp)){
            printf("%c",res);
        }
        //关闭文件  
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在使用 feof() 判断文件尾时,最后一行没有 \n 会少读一行

    #include 
    
    int main(){
        FILE *fp = fopen("test.txt", "w+");
    
        fputs("asd\n", fp);
        fputs("123456", fp);
        rewind(fp);
    
        char str[1024];
        while(fgets(str, 1024, fp) && !feof(fp)){
            printf("str = %s", str); 
            //输出 str = asd
            //若最后一行加上 \n,则输出 
            //str = asd
            //str = 123456
        }
        
        fclose(fp);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    读/写一个字符
    读入一个字符输出一个字符所在文件
    getchar()putchar()stdio.h
    fgetc(fp)fputc(ch,fp)stdio.h

    int fgetc(FILE *fp):从文件中读取一个字符,若到文件尾返回EOF

    • 正常情况返回一个int类型值
    • 读到文件尾或出错,返回 EOF
    #include 
    
    int main(){
        //打开文件
        FILE *fp = fopen("test.txt", "r+");
    
        //从文件中读取内容
        char res = EOF;
        while((res = fgetc(fp)) != EOF){
            printf("res = %c\n", res);
        }
    
        //关闭打开的文件
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    int fputc(int ch,FILE *fp):将ch字符写入文件

    • 写入成功,返回写入的字符
    • 写入失败,返回 EOF
    # include
    
    int main(){
       	//打开一个文件
        FILE *fp = fopen("test.txt","w+");
        
        //向文件中写入内容
        for(char ch = 'a';ch <= 'z';++ch){
           	char res = fputc(ch,fp);
            printf("%c",res);
        }
        
        //关闭打开的文件
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    读/写一行字符串
    读入字符串输出字符串所在文件
    getchar()putchar()stdio.h
    fgets(fp)fputs(s,fp)stdio.h

    char *fgets(char *s,int n,FILE *fp) :从 fp 指向的文件中读取 n-1 个字符,写入s中;如果中间遇到 \0 或者 EOF ,读入结束,且在字符串最后添加 \0

    • 正常,返回 char *str 指针
    • 遇到 \nEOF则停止读取
    • 出错,返回空指针 NULL
    #include 
    
    int main(){
        
        FILE *fp = fopen("test.txt", "w+");
    
        fputs("asd\n", fp);
        fputs("123456\n", fp);
        rewind(fp);
    
        char str[1024];
        fgets(str, 1024, fp);//读到 \n 读取一行结束
        printf("str = %s", str); // asd
    
        fclose(fp);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    #include 
    
    int main(){
        FILE *fp = fopen("test.txt", "w+");
        
        fputs("asd\n", fp);
        fputs("123456", fp);
        rewind(fp);
        
        char str[1024];
        
        while(fgets(str, 1024, fp)){//读到文件尾,停止读
            printf("str = %s", str);//asd123456
        }
        fclose(fp);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    int fputs(char *s,FILE *fp) :将 s 中的字符串写到 fp 指向的文件中

    • 正常则返回0
    • 出错则返回 EOF
    # include
    
    int main(){
        FILE *fp = fopen("test.txt","w+");
        
        fputs("Hello ",fp);
        fputs("World!",fp);
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    遇到 \0 自动终止写入

    # include
    
    int main(){
        FILE *fp = fopen("test.txt","w+");
        fputs("asd\0asdasd\n",fp);
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    格式读/写

    int fscanf(FILE *fp,char *format)

    读/写成功返回整数

    int fprintf(FILE *fp,char *fprmat)

    b. 二进制文件读/写

    二进制文件的读写函数可以读取文本文件

    文本文件的读写函数不可读取二进制文件

    unsigned fread(void *ptr,unsigned size,unsigned n,FILE *fp)

    从文件 fp 中读取 nsize 字节的数据块,存储于 ptr 指向的内存空间

    • 成功,则返回 n
    • 出错或文件结束,则返回0
    #include 
    
    int main(){
        // test.txt中存放的是"Hello\0 World!"
        FILE *fr = fopen("test.txt", "rb+");
        char buf[1024] = {0};
        
        int n = fread(buf, 1, 1024, fr);
        printf("%d\n", n);
        for(int i = 0; i < n; i++){
            printf("%c", buf[i]);
        }
        
        fclose(fr);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意:读取时,size 取最小字节,n 可以随便写

    • 若读取时 size 不是最小字节,则会引起读取失败

      如存储的 char 类型 0A 1E 1C 2C 66 67 68

      size = 1 时,n=1024 ,会将文件中内容依次取出

      size = 4 时,n=1024 ,第一个数据块 0A 1E 1C 2C 会顺利取出,但最后剩下3个字节不足一个数据块,则最后一个块读取不到


    unsigned fwrite(void *ptr,unsigned size,unsigned n,FILE *fp)

    ptr 指向的存储空间的 nsize 字节的数据块写入文件 fp

    • 成功,则返回 n
    • 出错或文件结束,则返回0
    # include
    
    int main(){
        FILE *fp = fopen("test.txt","wb+");
        char *str = "Hello\0 World!";
        
        fwrite((void *)str, 13 ,1, fp);
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    读写数组
    # include
    
    int main(){
        FILE *fp = fopen("test.txt","wb+");
       	int ages[4] = {1,3,5,7};
        fwrite(ages,sizeof(ages),1,fp);
        
        rewind(fp);
        
        int t;
        while(fread(&t,sizeof(int),1,fp) > 0){
            printf("data=%d\n",t);
        }
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    读写结构体

    结构体中的数据类型不统一,此时最适合用二进制的方式进行读写

    单个结构体

    # include
    
    typedef struct{
    	char *name;
        int age;
        double height;
    }Person;
    
    int main(){
        Person p1 = {"A",23,1.7};
        FILE *fp = fopen("test.person","wb+");
        fwrite(&p1,sizeof(p1),1,fp);
        
        rewind(fp);
        Person p2;
        fread(&p2,sizeof(p2),1,fp);
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    读写结构体数组

    # include
    
    typedef struct{
    	char *name;
        int age;
        double height;
    }Person;
    
    int main(){
        Person ps[] = {
            {"A", 18, 1.65},
          	{"B", 21, 1.88},
          	{"C", 33, 1.9}
        };
        
        FILE *fp = fopen("test.person","wb+");
        fwrite(&ps,sizeof(ps),1,fp);
        
        rewind(fp);
        Person p;
        while(fread(&p,sizeof(p),1,fp) > 0){
            printf("name = %s,age = %d,height = %lf\n"
                   ,p.name,p.age,p.height);
        }
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    8.2.4 文件操作函数

    a. 获取文件位置指针

    long ftell(FILE *fp) :返回距文件头的字节数

    • 成功,则返回整型
    • 失败,返回-1
    #include 
    
    int main(){
        char *str = "abcedfg";
        FILE *fp = fopen("test.txt", "w+");
    
        long p = ftell(fp);
        printf("p = %ld\n", cp); // 0
        
        // 写入一个字节
        fputc(str[0], fp);
        p = ftell(fp);
        printf("p = %ld\n", p); // 1
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    b. 位置指针重定位

    void rewind() :使位置指针指向文件头

    c. 文件定位函数

    int fseek(FILE *fp, long offset, int origin ); : 将位置指针移动到指定位置

    • fp :文件的指针,指向要操作的文件

    • offset :表示要移动的字节数

      offset 为正时,向后移动;

      offset 为负时,向前移动

    • origin:从何处开始计算偏移量。

      起始点常量名常量值
      文件开头SEEK_SET0
      当前位置SEEK_CUR1
      文件末尾SEEK_END2
    #include 
    
    int main(){
        FILE *fp = fopen("test.txt", "w+");
        fputs("123456789", fp);
        
        // 将文件指针移动到文件结尾
        fseek(fp, 0, SEEK_END);
        int len = ftell(fp); // 计算文件长度
        printf("len = %i\n", len);
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    #include 
    
    int main(){
        FILE *fp = fopen("test.txt","w+");
        
        fputs("123456789", fp);
        fseek( fp, 7, SEEK_SET );
        fputs("Hello", fp);
        
        fclose(fp);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    12657 - Boxes in a Line (UVA)
    Docker容器:网络模式与资源控制
    codesys虚轴
    Matter理论教程-通用-1-01:理论详解
    ATF官方文档翻译(二):Authentication Framework & Chain of Trust(身份验证框架和信任链)(1)
    Redis系列:Redis的数据结构
    Docker默认桥接网络是如何工作的
    【SpringCloud-Alibaba系列教程】12.日志链路追踪
    Redis_04_Redis事务
    线性规划学习
  • 原文地址:https://blog.csdn.net/qq_40479037/article/details/126208368