美文网首页
C语言09- 文件

C语言09- 文件

作者: sanpintian | 来源:发表于2018-01-08 11:27 被阅读0次

    19:文件

    文件:是一组相关数据的有序结合

    19.1:文件概念

    文件分类:

    1. 普通文件:存储在磁盘等外部设备中,在需要的时候由程序将数据读入内存
    2. 设备文件:外部设备对于操作系统来说也是当做一个文件进行管理,把它们的输入、输出等同于对磁盘文件的读和写。比如显示器、打印机、键盘等。
    3. 文件夹:包含普通文件和子文件夹

    文件系统:操作系统中用于组织和管理磁盘上文件的方法以及数据结构。

    文件系统作用:为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。程序中文件操作,之后都由文件系统去替程序完成。

    文件系统有:

    1. Windows: FAT,NTFS
    2. Linux:Ext2,Ext3,Ext4
    3. Solaris:ZFS(Linux一直想移植,但由于协议冲突等等一直没有实现)
    4. 其他等
    VFS.png

    如上图文件系统可以理解为三层:

    1. 最上层文件系统的系统调用
    2. 虚拟文件系统 VFS(Virtual Filesystem Switch)
    3. 挂载到VFS中的各实际文件系统

    ZFS是一款128bit文件系统,总容量是现有64bit文件系统的1.84x1019倍,其支持的单个存储卷容量达到16EiB(264byte,即 16x1024x1024TB);一个zpool存储池可以拥有264个卷,总容量最大256ZiB(278byte);整个系统又可以拥有2^64个存储 池。可以说在相当长的未来时间内,ZFS几乎不太可能出现存储空间不足的问题。另外,它还拥有自优化,自动校验数据完整性,存储池/卷系统易管理等诸多优点。较ext3系统有较大运行速率,提高大约30%-40%。


    文本文件与二进制文件:

    1. 文本文件:基于字符编码,以固定长度的二进制序列进行编码和解码(常见的有ASCII文编码和Unicode编码);(使用notepad就可以读取);(纯文本文件:.c文件.txt.html等)
    2. 二进制文件:基于值编码的文件,二进制文件编码是变长的,具体的长度由具体的格式决定,比如EXE或者BMP二进制文件;(需要专门的工具读取,比如图片就需要专门的读图软件才能打开,如果用notepad打开,就会看见不少乱码);(二进制文件:exe\dll\jpg\png\avi\doc\pdf等)
    文本“5678”的存储形式为:字符的ASCII码: 00110101 00110110 00110111 00111000 (四个字节)
    值5678的存储形式为:值的二进制: 00010110 00101110 (两个字节)
    

    19.2:文件创建打开与读写

    19.2.1:打开文件fopen_s

    //文件读写:fopen(), fopen_s()

    函数原型:FILE * fopen(const char * path, const char * mode);
    返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回 NULL,并把错误代码存在errno中。
    参数说明:
    参数 path字符串包含欲打开的文件路径及文件名,参数 mode 字符串则代表着流形态。
    
    一般而言,打开文件后会做一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以一般在 fopen() 后作错误判断及处理。
    
    //fopen("newfile.txt", "rw, ccs=UTF-8");//默认为ANSI
    //fopen是C标准IO库的函数,与非C标准库函数open()函数相比,用fopen打开的文件读写是带缓存的,即用fwrite向文件里写一个字节,一般来讲它不会立刻调用write将该操作提交给kernel,而是积累到一定程度再一起写。
    
    //fopen_s()函数是用于fopen()的新的安全版本。现在都推荐使用fopen_s()来打开文件。它的调用方法:
    
    FILE *pfile=NULL;
    errno_t err = fopen_s(&pfile,FILENAME,"wb+");
    
    if(err!=0 || pfile==NULL) {
            return -1;
    }
    
    fclose(pfile);完成文件IO后,不要忘调用fclose()函数将文件关闭。
    
    fopen()函数.png

    19.2.2:读写文件

    在C语言里,可以使用fread/fwrite,fscanf/fprintf,fgets/fputs,fgetc/fputc等函数来进行文件的读写。

    C语言中文件读写几种类型:

    1. 二进制文件读写
    2. 格式化输入输出到文本文件
    3. 字符输入输出到文本文件
    4. 字符串输入输出到文本文件
    //二进制文件读写
    int binary_io() {
         //打开或者创建文件
         char *path = "h:\\doc\\new.txt";
        
         FILE *fp1 = NULL;
         errno_t err;
    
         err = fopen_s(&fp1,path,"w");
    
         if(fp1==NULL || err != 0) {
             printf("Open file failed\n");
             return -1;
         }
    
         //基于fp1这个指针,对文件进行读写等操作
         char buff[]="hello world";
         fwrite(buff,sizeof(buff),1,fp1);
    
         int data = 0x10;
         fwrite(&data,sizeof(data),1,fp1);
    
         fclose(fp1);
    
         //读数据
         err = fopen_s(&fp1,path,"r");
         
         if(fp1==NULL || err!=0) {
             return -1;
         }
    
         data = 0;
         memset(buff,0,sizeof(buff));
    
         fread(buff,sizeof(buff),1,fp1);
         printf("buff:%s\n", buff);
    
         fread(&data,sizeof(data),1,fp1);
         printf("data:0x%x\n", data);
         fclose(fp1);
    
         return 0;
    }
    
    //格式化输入输出到文本文件(将除了ascci之外的数据以文本的方式写入文件)
    int format_io() {
         char *file="h:\\doc\\1.txt";
         FILE *pfile=NULL;
    
         errno_t err = fopen_s(&pfile,file,"w");
    
         if(err!=0 || pfile==NULL){
             printf("Open file failed\n");
             return -1;
         }
     
         fprintf(pfile,"%s %x %lf","hello-world", 0x10,3.1415);
         fclose(pfile);
    
         char buff[64]={0};
         int data=0;
         double d = 0.0;
     
         err=fopen_s(&pfile,file,"r");
    
         if(err!=0) {
             printf("Open file failed\n");
             return -1;
         }
         
         fscanf_s(pfile,"%s%x%lf",buff,64,&data,&d);
         printf("buff:%s,data:%d,d:%lf\n",buff,data,d);
    
         fclose(pfile);
    
         return 0;
    }
    
    //字符输入输出到文本文件
     char *str="hello world, goodbye world!";
     while(*str!='\0') {
             fputc(*str,pfile);
             str++;
    }
    
    //字符串输入输出到文本文件
    
    
    

    19.3:文件其他相关操作

    1. fseek(被打开文件的指针, 移动的偏移-偏移值可以为正或者为负,代表第二个参数的偏移相对于什么位置):移动文件的当前读写位置指针。fseek(fp,50,SEEK_CUR);将文件的读写指针移动到当前位置后面50个字节。而SEEK_SET则是相对于文件开头,SEEK_END是文件结尾。fseek(fp, -50, SEEK_END);就是将文件读写指针移动到距离文件结束50个字节的位置。
    2. rewind():rewind(fp)执行函数后,会将文件fp当前的读写位置移动到文件的开头位置。等同于:fseek(fp,0,0);
    3. feof():用来判断文件当前位置是否达到文件末尾,如果到达,就返回真,否则为假。
    4. rename/remove/mkdir:文件的重命名,删除,创建文件夹都是与文件有关的一些基本操作。
    5. ftell():用于获取文件读写指针的当前位置。可以结合fseek()函数来计算文件的大小。

    19.4:结构体IO与优化

    //定义结构体:
    
    #define MAXLEN 64
    
    typedef struct _record {
        char name[MAXLEN];
        int age;
    }record,*precord;
    
    record  r =  {“tom”,25};
    
    //按下方法将r写入文件,导致r成员name[MAXLEN]中大量零被写入文件中存放很多无用数据零。这样直接写入不是最佳方法:
    fwrite(&r,sizeof(r),1,fp);
    
    //考虑将结构体r按格式写入文件:
    //假如name[MAXLEN]中的有效字符个数为len,那么写入方法为:
    Len+name+age
    
    //也就是先将name的字符数len写入文件,接着写入name的有效字符数据,再写入年龄数据。其中len和age各为4个字节的整数,name为字符。比如对于下面结构体记录数据:
    record  r1  =  {“tom”,25};
    record  r2  =  {“lily”,22};
    
    //3”tom”25 4”lily”22;这样在每个name前面都用一个长度来记录name中字符的个数,就可以避免将过多的无用的零写入文件了。如下
    
    int opt_write_file(FILE *fp) {
        char ch;
        
        do {
            record rcd={0};
            printf("Please input name and age\n");
                
            scanf_s("%s%d", rcd.name,MAXLEN,&rcd.age);
                
            size_t len = strlen(rcd.name);  
            fwrite(&len,sizeof(len),1,fp);//先写入name中字符的个数
            fwrite(rcd.name,len,1,fp);//接着写入name字符数
            fwrite(&rcd.age,sizeof(int),1,fp);//再写入年龄
        
            printf("input q to quit,else to continue\n");       
            //scanf_s("%c",&ch,1);
            //fflush(stdin);
                
            ch = _getch();
            if(ch=='q')
                
            break;
        } while (1);
        
        return 0;
    
    }
    
    int opt_read_file(FILE *fp) {
        while(!feof(fp)) {
            record rcd = {0};
            size_t len=0;
            int res = fread(&len,sizeof(len),1,fp);//先读取name的字符数
            if(res == 0) {
                    return 0;
            }
                
            fread(rcd.name,len,1,fp);//再按照字符数读取name
            fread(&rcd.age,sizeof(rcd.age),1,fp);//再读取年龄
            printf("name:%s,age:%d,res:%d\n", rcd.name,rcd.age,res); 
        }
    
        return 0;
    }
    
    

    相关文章

      网友评论

          本文标题:C语言09- 文件

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