• C/C++(文件操作)


    文件

    读写磁盘文件

    文件流

    文件看作是一个字符的序列,即文件是由一个一个字符组成的字符流,因此C语言也将称之为文件流。当读写一个文件时,可以不必关心文件的格式或者结构。

    文件类型

    划分依据是逻辑关系

    文本文件:以ASCII个是存放,一个字节存放一个字符。便于字符的逐个处理,但占用空间较多,需要花费时间转移。
    二进制文件:以补码的编码格式存放,二进制文件是把数据以二进制数的格式存放在文件中,占用空间较小,数据按其内存中的存储形式鸳鸯存放。
    数值写的时候有两种格式(文本,二进制),而文本写的时候文本文件和二进制文件是一样的。

    文件缓冲

    从内存中读取数据比从文件中读取数据要快的多。
    对文件的读写需要用到open,read,write等系统底层函数,而用户进程每调用一次系统函数都要从永华态切换到内核态。执行完毕后再返回,这样花费时间成本。
    window与linux是有区别的

    int main() {
        printf("hello world");
        while(1);
        return 0;
    }
    //windows 下照样输出
    //linux 下无法输出(printf("hello world
    ");上述换成此句即可输出,
    有刷掉缓存的功能)
    

    文件的打开与关闭

    通过fopen打开一个文件,返回一个FILE *型指针。以后的所有对文件的操作也就是对FILE * 指针操作。

    FILE结构体和FILE *指针

    typedef struct {
        short level; /* 缓冲区满/空程度 */
        unsigned flags; /* 文件状态标志 */
        char fd; /* 文件描述符 */
        unsigned char hold; /* 若无缓冲区不读取字符 */
        short bsize; /*  缓冲区大小 */
        unsigned char *buffer; /*  数据传送缓冲区位置 */
        unsigned char *curp; /*  当前读写位置 */
        unsigned istemp; /* 临时文件指示 */
        short token; /* 用作无效检测 */
    } FILE ; /* 结构体类型名 FILE */
    

    在开始执行程序的时候,将自动打开 3 个文件和相关的流:标准输入流(stdin)、标准输出流(stdout)和标准错误(stderr),它们都是 FIEL*型的指针。流提供了文件和程序的
    通信通道。

    int main() {
        FILE * pf = fopen("data.txt","w");//w,通过写的方式打开文件data.txt,一打开就缓冲到内存中,以后操作pf(windos中交句柄)
    
        return 0;
    }
    

    fopen(padth,mode);

    mode:
    r:以只读的方式打开,如果文件不存在,则报错,文件不可写。
    w:如果文件不存在,则创建,如果文件存在会覆盖文件,文件不可读。
    a:(追加写)如果文件不存在,则创建,如果文件存在文件不可读。
    r+ 可读/可写 文件不存在时报错,文件存在打开文件
    w+ 可读/可写 文件不存在时创建,文件存在时会覆盖文件
    a+ 读取/追加 文件不存在时创建,文件存在时在后面追加
    如果都写的文件是二进制文件,则还需加b,eg:rb,rb+等,unix/linux不区分文本和二进制文件。

    fclose()

    fclose()用来关闭先前 fopen()打开的文件. 此动作会让缓冲区内的数据写入文件中, 并释放系统所提供的文件资源.

    int main() {
        FILE * pf = fopen("data.txt","w");
        for(char ch = 'a';ch <= 'z';ch++) {
            fputc(ch,pf);//向pf中写入
        }
        fclose(pf);//主动刷新缓存,之前是没有写入的,如果不加等进程结束之后系统刷新。一般情况下要加,如果不加,在进程未结束之前还有突发情况(断电,硬件故障等)。而且还有释放缓存中的数据。
    
        return 0;
    }
    

    一次读写一个字符(文本操作)

    fputc(int ch,FILE * stream)

    将ch字符写入文件,stream:指向文件缓冲的指针,int:需要写入的字符。返回值int写入成功返回成功字符,失败返回EOF。

    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    //宏的定义必须是一行
    
    int main() {
        FILE *pf = fopen("xx.txt","w+");
        /*if(pf == NULL) {
            printf("open error!
    ");
            exit(-1);
        }*/ //判断每次要写,可以写成宏的形式
        F_PRINTF_ERROR(pf);
        putchar( fputc('a',pf) );//向pf中写入字符a.并且用putchar打印。
        fclose(pf);//释放
        return 0;
    }
    

    fgetc()读文件

    读文件是需要判断是否结束,结束的标识EOF

    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    
    int main() {
        FILE * pf = fopen("data.txt","r+");
        F_PRINTF_ERROR(pf);
        char ch = fgetc(pf);//结尾或者失败返回EOF
        putchar(ch);
    
        char ch = fgetc(pf);
        putchar(ch);//一次读取一个字节
        //假如文件中有4个字节,读取5次以上返回EOF
       
        //这时候可根据EOF条件进行循环
    #if 0
        char ch;
        while( (ch = fgetc(pf)) != EOF) {//注意赋值运算和关系运算的优先级,赋值关系优先级倒数第二
            putchar(ch);
        }
    #endif
    
        fclose(pf);
        return 0;
    }
    

    拷贝文件的实现

    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    
    int main() {
        //先要都一个文件
        FILE * pfr = fopen("path...","r");
        F_PRINTF_ERROR(pfr);
        //写入文件
        FILE * pfw = fopen("path","w+");
        F_PRINTF_ERROR(pfw);
        //利用循环将读出来的文件进行写入
        while( (ch = fgetc(pfr)) != EOF ) {
            putchar(fputc(ch,pfw));
        }
        //最后释放
        fclose(pfr);
        fclose(pfw);
    
        return 0;
    }
    

    fputc(int ch,FILE * stream)

    将ch字符写入文件,成功返回写入字符,失败返回EOF。
    重点是判断结束条件是什么?通常的做法是一句返回值

    feof的问题

    检测到文件结尾返回1,0未结束。会导致多读一个字符,标志位检测之后所导致的。标志位检测之后所导致的。eg:读abcd,feof读的时候有一个标识flag = 0;每读一次指针向后推移,改变flag的状态,如果有值重新赋值为0,没有值flag=1,最后末尾添加-1。首先读一次,在循环输出,在读也可解决。

    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    
    int main() {
        FILE * pf = fopen("data.txt","w");
        for(char ch = 'a';ch <= 'z';ch++) {
            fputc(ch,pf);//向pf中写入
        }
        char ch;
        while(!feof(ch)) {
            ch = fgetc(pf);
            printf("%x->%c
    ",ch,ch);
        }
        fclose(pf);
    
        return 0;
    }
    
    
    char ch;
    ch = fgetc(pf);//首先获取第一个字符
    while(!feof(pf)) {
        printf("%x->%c
    ",ch,ch);//获取的第一个字符输出
        ch = fgetc(ch);//紧接着获取
    }
    

    改进:

    char ch;
    while((ch = fgetc(pf)) && !feof(pf)) {
        printf("%x->%c
    ",ch,ch);
    }
    

    不建议使用

    文件的加密与解密

    文件加密:

    #defined CODE 10
    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    
    int main() {
        FILE * pfSrc = fopen("main.c","r+");
        F_PRINTF_ERROR(pfSrc);
        FILE * pfDec = fopen("mainIn.c","w+");
        F_PRINTF_ERROR(pfDec);
    
        char ch;
        while((ch = fgetc(pfSrc)) !=EOF) {
            ch += CODE;
            fputc(ch,pfDec);
        }
        fclose(pfSrc);
        fclose(pfDec);
    
        return 0;
    }
    
    

    文件的解密:

    #defined CODE 10
    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    //读的文件换一下
    int main() {
        FILE * pfSrc = fopen("mainIn.c","r+");
        F_PRINTF_ERROR(pfSrc);
        FILE * pfDec = fopen("mainDein.c","w+");
        F_PRINTF_ERROR(pfDec);
    
        char ch;
        while((ch = fgetc(pfSrc)) !=EOF) {
            ch -= CODE;
            fputc(ch,pfDec);
        }
        fclose(pfSrc);
        fclose(pfDec);
    
        return 0;
    }
    

    打开要读的文件,同时打开要写的文件,对读到的文件进行加工操作后写入到要输出的文件中。
    问题:加密的时候加密的数字太大会产生溢出

    一次读一行字符(文本操作)

    行:有回车就算行。linux下0a字符表示换行,windows下0d表示换行,如果把Windows下的文件拖到Linux下,则表示换行的文件无法解析。
    同样在Windows下写的文件,在Linux中读的时候有差异。

    fputs

    写一行文件

    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    
    int main() {
        FILE * pf = fopen("xxx.txt","w");
        F_PRINTF_ERROR(pf);
    
        fputs("aaa
    aaaa
    ");
        fputs("bbbbbbb
    ");
        fputs("ccccccc
    ");//往里写遇到此行结束
    
        fclose(pf);
        return 0;
    }
    
    

    fgets

    fgets(int buf,int size,LIFE * pf)按行读文件

    再去读n-1个字符前遇到了 ,连同 一并读进去了,并在其后也添加了
    在去读n-1既没有遇到 也没有遇到EOF,此时就读到了n-1个字符,并在其后添加了
    在去读n-1既没有遇到 ,遇到EOF,并其后添加

    #defined F_PRINTF_ERROR(e)
    do{
        if(e == NULL) {
            printf("open error");
            exit(-1);
        }
    }while(0)
    
    int main() {
        FILE * pf = fopen("xxx.txt","r");
        F_PRINTF_ERROR(pf);
    
        char buf[1024];
        fgets(buf,1024,pf);//只读一行字符 aaa
    
    
        fclose(pf);
        return 0;
    }
    

    test:fgets( buf, 10, fp);一下文件fgets共执行了多少次?

    1234567890abcdefg
    1234567890
    abcdefg(
    ) 有无
    都会去读下一行的判断
    
    第一次:1-9 
    第二次:0-g 
    
    第三次:1-9 
    第四次:0   
    
    第五次:a-g 
    第六次:判断下一行
    
    
    int main() {
        FILE * pf = fopen("aaa.txt","r+");
        char buf = [1024];
        while(fgetc(buf,1024,pf) != NULL) {//判断条件
            printf("%sx",buf);
        }
        fclose(pf);
    
        return 0;
    }
    

    读取的返回值:
    当遇到 EOF的时候返回非控,在EOF以后,再去读的时候NULL

    fgets的eof问题

    int main() {
        FILE *pf = fopen("xxx.txt","w+");
        if(NULL == pf)
            exit(-1);
        fputs("aaaaaaaaa
    ",pf);
        fputs("bbbbbbbbb
    ",pf);
        fputs("ccccccccc
    ",pf);
        fputs("dddddddddd",pf);
    
        rewind(pf);//让指针重新指向第一个
        char buf[1024];
        /*
        while(fgets(buf,1024,pf) && !feof(pf)) {
            printf("%s",buf);
        }*/ //会多读了一行
        while(fgets(buf,1024,pf) != NULL) {//效果会更好,避免了一些坑
            printf("%s",buf);
        }//相对于更好
        return 0;
    }
    

    案例:从配置文件中读取用户名,和输入的用户名进行匹配。
    从配置文件中读到用户名模拟出一个登录功能,从界面输入一个用户名,进行匹配对比。

    xxx.ini文件

    assassin  //注意有两个空格
    

    main.c文件

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    int main() {
        FILE * pf = fopen("xxx.ini","r+");
        if(NULL == pf) {
            exit(-1);
        }
        char name[1024];
        scanf("%s",name);
        char buf[1024];
        fgets(buf,1024,pf);
        if(strcmp(name,buf) == 0) {
            printf("欢迎登录!
    ");
        }else {
            printf("登录失败!
    ");
        }
    
        return 0;
    }
    

    改进,在上述中如果不小心输入空格就会匹配不成功,过滤

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    int main() {
        FILE * pf = fopen("xxx.ini","r+");
        if(NULL == pf) {
            exit(-1);
        }
        char name[1024];
        scanf("%s",name);
        char buf[1024];
        fgets(buf,1024,pf);
    
        
        char *p = buf;
        while(*p) p++;//p到的位置
        p--;//p回到的前一个位置
        while(*p == "	") {
            *p = "";
            p--;
        }
    
        if(strcmp(name,buf) == 0) {
            printf("欢迎登录!
    ");
        }else {
            printf("登录失败!
    ");
        }
    
        return 0;
    }
    

    test:读配置文件,过滤掉以#开头的注释行和空行
    注:空行(?)是以 开头的行,注释行是以#开头的行。

    #include<stdio.h>
    
    int main() {
        FILE *pf = fopen("smb.conf","r+");
        if(NULL == pf)
            exit(-1);
    
        char buf[1024];//一行全能读完
        FILE *pfbak = fopen("smb.conf.bak","w");//用来做备份的文件
        if(NULL == pfbak) {
            fclose(pf);//关闭读的文件
            exit(-1);
        }
        //配置文件有个不成文的规定每一行不能超过1024个字节
        while(fgets(buf,1024,pf)) {
            if(*buf == "#" || *buf == "
    ") {//匹配buf中的内容
                continue;
            }
            printf("%s",buf);
            fputs(buf,pfbak);
        }
        
        fclose(pf);
        fclose(pfbak);
        return 0;
    }
    

    test:文本等号以后就和:
    atoi(),函数过滤函数。

    一次读写一块字符(二进制操作)

    文本文件以结束(写),要么以 结束(读),FOF(0xff),, 等是文本重要的标识,而二进制则往往是以块的形式写入或者读出。所有的二进制接口对于这些标识是不敏感的。

    fwrite/fread

    函数声明:

    int fwrite(void *buffer,int num_bytes,int count,FILE *fp)
    buffer: 代表即将要放数据的空间,
    num_byte: 每次写的最小单元
    count: 总共写的次数
    fp: 写的目标文件
    int fread(void *buffer,int num_bytes,int count,FILE *fp)
    

    eg:

    int main() {
        char buf[1024] = "a
    bcdefg";
        FILE *pfa = fopen("xxx.txt","w+");
        fputs(buf,pfa);//实际文件中写入了a bc
    
        char readBuf = [1024];
        rewind(pfa);//让指向末尾的指针回到起始的地方
        fgets(readBuf,1024,pfa);//读写入的文件,读文件时结束位
    位标识
        printf("%s",readBuf);//只输出a
    
        fclose(pfa);
        printf("
    =========
    ");
        
        FILE *pfb = fopen("yyy.txt","wb+");//wb是二进制操作的标识
        fwrite((void*)buf,1,8,pfb);
        rewind(pfd);
        fread((void*)readBuf,1,8,pfd);
        for(int i = 0;i < 8;i++) {
            printf("%x->%c
    ",readBuf[i],readBuf[i]);
        }
    
        fclose(pfb);
    
        return 0;
    }
    /*
    a
    =======
    61->a
    a->
    
    62->b
    63->c
    0->
    64->d
    65->e
    66->f
    
    */
    
    

    二进制和文本的读写

    int main() {
        //以文本的形式写:
        FILE *pf = fopen("mm.txt","w+");
        int arr[10] = {0,1,0xffffffff,2,3,4,5,6,7,8};
        fputs((char*)arr,pf);//一个也写不进去,fputs是写文本的。
        fclose(pf);
        
        //以二进制的形式读写:
        FILE *pff = fopen("jj.txt","wb+");
        int arr1[10] = {0,1,0xffffffff,2,3,4,5,6,7,8};
        fwrite((void*)arr1,4,10,pff);
        //fgets不能读,因为fgets 遇到
    ,EOF(-1),文本结束就会结束。
        rewind(pff);
        int arr2[10];
        fread((void*)arr2,4,10,pff);//读文件
        for(int i = 0;i < 10;i++) {
            printf("%d
    ",arr2[i]);
        }
            
        fclose(pff);//能写入但是是乱码。
        
        return 0;
    }
    
    

    返回值陷阱

    二进制没有 ,EOF,len-1作为都出的结束标识,fread依靠读出块多少来标识读结果和文件结束标志。以最小单元格式进行读,或者以写入的最小单元进行读。

    int main() {
        char buf[1024] = "12345678";
        FILE *pf = fopen("xx.txt","w+");
        if(NULL == pf)
            exit(-1);
        //fwrite((void*)buf,1,8,pf);
        fwrite((void*)buf,8,1,pf);//这两种写法是没有区别的但是读的时候有差别
    
        //读到完整块的个数
        rewind(pf);
        int n;
        char read[10];
        n = fread((void*)read,1,8,pf);
        printf("n = %d
    ",n);//n = 8
        n = fread((void*)read,1,8,pf);
        printf("n = %d
    ",n);//n = 0
    //读到的是整个块为单位,返回块的个数
    /*
        n = fread((void*)read,8,1,pf);
        printf("n = %d
    ",n);//n = 1
        n = fread((void*)read,8,1,pf);
        printf("n = %d
    ",n);//n = 0
    */
        n = fread((void*)read,1,7,pf);
        printf("n = %d
    ",n);//n = 1
        n = fread((void*)read,1,7,pf);
        printf("n = %d
    ",n);//n = 0
        //
        n = fread((void*)read,1,3,pf);
        printf("n = %d
    ",n);//n = 3
        n = fread((void*)read,1,3,pf);
        printf("n = %d
    ",n);//n = 3
        n = fread((void*)read,1,3,pf);
        printf("n = %d
    ",n);//n = 2
        n = fread((void*)read,1,3,pf);
        printf("n = %d
    ",n);//n = 0
    //一般情况下都是最小单位为1,这样便于遍历
        while((n = fread( (void*)read,1,3,pf) )>0) {
            for(int i = 0;i < 3;i++) {
                printf("%c",read[i]);
            }
        }
        //12345678
    
        fclose(pf);
    
        return 0;
    }
    

    一般来说读的单位是写入的最小单位决定的

    int main() {
        int arr[10] = {1,2,3,4,5,6,7,8,9,10};
        FILE *pf = fopen("xx.txt","w+");
    
        fwrite((void*)arr,4,10,pf);
        rewind(pf);
        int n = 10;
        while((n = fread( (void*)arr,4,1,pf)) > 0) {
            for(int i = 0;i < n;i++) {
                printf("%d
    ",arr[i]);
            }
        }
    }
    
    
  • 相关阅读:
    Angular之filter学习
    Jupyter notebook 安装,初步使用
    Python排序算法
    获取相对于控件的鼠标坐标
    使用PYTHON实现docx文档的读写
    MATLAB 物体识别算法说明:vision.ForegroundDetector, vision.BlobAnalysis
    MATLAB 例子研究 Motion-Based Multiple Object Tracking
    MATLAB 图像处理——Contrast Enhancement Techniques
    MATLAB 图像操作基础
    MATLAB 图像分类 Image Category Classification Using Bag of Features
  • 原文地址:https://www.cnblogs.com/intelwisd/p/8414832.html
Copyright © 2020-2023  润新知