C_文件操作(精讲)

目录

知识点1【文件的概述】(了解)

 案例

知识点2【磁盘文件分类】(了解)

文本文件:

二进制文件:

文本文件的优点:

二进制文件的优点:

知识点3【文件指针】(了解)

知识点4【操作文件的库函数】(了解)

1、fopen打开文件

2、关闭文件 fclose

3、一次读写一个字符

案例1:fputc写操作

案例2:fgetc读操作

4、一次读写一个字符串

案例1:读操作

案例2:写操作

5、文件块的读写fread fwrite 内存数据原样 输出到磁盘

文件块的写

文件块的写

6、文件块的格式化读写fprintf(写) fscanf(读)

 案例

总结:

知识点5【文件的随机读写】(重要)

知识点的引入:

文件的随机读写:移动文件的流指针

1、rewind 复位文件流指针

2、ftell 测文件读写位置距文件开始有多少个字节

3、fseek 定位位置指针(读写位置)

案例1:将文件流指针 定位到文件的尾部

案例2:将文件数据 一次性读取到内存

综合案例:文件加密器

详细设计API设计参考

废话不多说了上程序(完全注释):


知识点1【文件的概述】(了解)

磁盘文件:文件用来存放程序、文档、音频、视频数据、图片等数据的。

设备文件:在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文 件的读和写

将缓冲区数据 写入文件的方式:

        1、满刷新:数据写满缓冲区时 数据才写入文件

        2、行刷新:缓冲区数据 遇到换行符 将数据写入文件,printf("hellword\n");

        3、强制刷新:fflush(stdout);

        4、关闭刷新

 案例

#include <stdio.h>
#include <unistd.h>

void test00(){
    int time = 0;
    while(1){
        printf("\r\t\t\t\t\t%02d:%02d", time/60, time%60);
        fflush(stdout);
        sleep(1);
        time++;
    }
}

int main(int argc, char const *argv[])
{
    test00();
    return 0;
}

知识点2【磁盘文件分类】(了解)

磁盘文件 在物理上 都是二进制存储。

        文本文件:基于字符编码的文件

        二进制文件:基于值编码的文件 (内存数据原样 输出到磁盘)

文本文件:

        基于字符编码,常见编码有 ASCII、UNICODE 等 一般可以使用文本编辑器直接打开

        例如:数 5678 的以 ASCII 存储形式为: ASCII 码:00110101 00110110 00110111 00111000 歌词文件(lrc):文本文件

二进制文件:

        基于值编码,自己根据具体应用,指定某个值是什么意思

        把内存中的数据按其在内存中的存储形式原样输出到磁盘上

        一般需要自己判断或使用特定软件分析数据格式

        例如:数 5678 的存储形式为: 二进制码:00010110 00101110

文本文件的优点:

        便于用户阅读,用于用户查看

二进制文件的优点:

        不需要转换, 文件移动、拷贝、加密

知识点3【文件指针】(了解)

知识点4【操作文件的库函数】(了解)

1、fopen打开文件

#include <stdio.h>
FILE *fopen(const char *path, const char *mode);

        mode

读写权限:r读   w写   a追加    +可读可写   t文本文件(省略)  b二进制文件

r:以只读方式打开文件

        文件不存在返回 NULL

        文件存在返回文件指针,进行后续的读操作

w:以只写方式打开文件

        文件不存在,以指定文件名创建此文件,并且打开文件;

        若文件存在,清空文件内容,打开文件,然后进行写操作;

        如果文件打不开(比如文件只读),返回 NULL

a:以追加方式打开文件

        文件不存在,以指定文件名创建此文件(同 w)

        若文件存在,从文件的结尾处进行写操作

2、关闭文件 fclose

#include <stdio.h>
int fclose(FILE *fp);

3、一次读写一个字符

int fgetc(FILE *stream)//读操作

返回值:

        以 t 的方式: 读到文件结尾返回 EOF

        以 b 的方式:读到文件结尾,使用 feof(后面会讲)

int fputc(int c, FILE *stream)//写操作
fputc 将 c 的值写到 stream

返回值:

        如果输出成功,则返回输出的字节值;

        如果输出失败,则返回一个 EOF

EOF 是在 stdio.h 文件中定义的符号

案例1:fputc写操作

void test01()
{
    FILE *fp = NULL;
    fp = fopen("a.txt", "w");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    char buf[1024]="";
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf)-1] = 0;

    int i=0;
    while(buf[i] != '\0')
    {
        fputc(buf[i++], fp);
    }

    fclose(fp);
}

案例2:fgetc读操作

void test02()
{
    FILE *fp = NULL;
    fp = fopen("a.txt", "r");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    char buf[1024]="";
    int i=0;
    while((buf[i++] = fgetc(fp)) != EOF);
    buf[strlen(buf)-1]=0;
    
    printf("%s\n", buf);

    fclose(fp);
}

4、一次读写一个字符串

读操作

char *fgets(char *s, int size, FILE *stream)

从 stream 所指的文件中读取字符,在读取的时候碰到换行符或者是碰到文件的末尾停止读取。

或者是读取了 size-1 个字节停止读取,在读取的内容后面会加一个\0,作为字符串的结尾

返回值:

        成功返回目的数组的首地址,即 s

        失败返回 NUL

案例1:读操作

void test02()
{
    FILE *fp = NULL;
    fp = fopen("a.txt", "r");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    char buf[1024]="";
    while(fgets(buf, sizeof(buf), fp) != NULL)
    {
        printf("##%s##\n", buf);
        printf("##%d##\n", strlen(buf));
    }

    fclose(fp);
}
int fputs(const char *s, FILE *stream);

案例2:写操作

void test03()
{
    FILE *fp = NULL;
    fp = fopen("c.txt", "w");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    char *buf[]={"hello world\n", "hello world\n", "hello world"};
    int n = sizeof(buf)/sizeof(buf[0]);

    int i=0;
    for ( i = 0; i < n; i++)
    {
        fputs(buf[i], fp);
    }
    
    fclose(fp);
}

5、文件块的读写fread fwrite 内存数据原样 输出到磁盘

        返回的是整块数 不足一块 不算的

文件块的写

void test04()
{
    HERO hero_buf[]={{"德玛西亚", 80, 60}, {"小炮", 40, 80}, {"小法",50, 90}};
    
    FILE *fp = NULL;
    fp = fopen("hero.txt", "w");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    fwrite(hero_buf, sizeof(HERO), 3, fp);
    
    fclose(fp);

}

fwrite将内存数据原样输出到磁盘 而编辑器打开文件时 做了ASCII转换 会出现乱码

不方便用户查看 但不影响用户读文件数据

文件块的写

void test05()
{
    HERO hero_buf[3];
    memset(hero_buf, 0, sizeof(hero_buf));
    
    FILE *fp = NULL;
    fp = fopen("hero.txt", "r");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    fread(hero_buf, sizeof(HERO), 3, fp);

    int  i=0;
    for ( i = 0; i < 3; i++)
    {
        printf("%s %d %d\n", hero_buf[i].name, hero_buf[i].def,hero_buf[i].atk);
    }
    
    fclose(fp);
}

fread fwrite用于文件的拷贝、移动 一般不用于用户查看

6、文件块的格式化读写fprintf(写) fscanf(读)

 案例

void test06()
{
    HERO hero_buf[]={{"德玛西亚", 80, 60}, {"小炮", 40, 80}, {"小法",50, 90}};
    
    FILE *fp = NULL;
    fp = fopen("hero.txt", "w");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    int i=0;
    for ( i = 0; i < 3; i++)
    {
        fprintf(fp,"姓名:%s 防御:%d 攻击:%d\n", \
        hero_buf[i].name,hero_buf[i].def,hero_buf[i].atk);
    }
    
    fclose(fp);
}
void test07()
{
    HERO hero_buf[3];
    memset(hero_buf, 0, sizeof(hero_buf));
    
    FILE *fp = NULL;
    fp = fopen("hero.txt", "r");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    int  i=0;
    for ( i = 0; i < 3; i++)
    {
        fscanf(fp,"姓名:%s 防御:%d 攻击:%d\n", \
        hero_buf[i].name, &hero_buf[i].def,&hero_buf[i].atk);
    }

    for ( i = 0; i < 3; i++)
    {
        printf("%s %d %d\n", hero_buf[i].name, hero_buf[i].def,hero_buf[i].atk);
    }
    
    fclose(fp);
}

总结:

        字节操作:fgetc fputc

        字符串操作:fgets fputs

        块操作:fread fwrite

        格式化操作:fscanf fprintf

知识点5【文件的随机读写】(重要)

文件默认 顺序读写

知识点的引入:

void test01()
{
    FILE *fp = NULL;
    fp = fopen("c.txt", "w+");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    fputs("hello world", fp);
    fclose(fp);
    
    fp = fopen("c.txt", "r");

    char buf[1024]="";
    fgets(buf, sizeof(buf), fp);
    printf("buf=%s\n",buf);
    
    fclose(fp);
}

文件的随机读写:移动文件的流指针

        rewind ftell fseek

1、rewind 复位文件流指针

void rewind(FILE *stream)
void test01()
{
    FILE *fp = NULL;
    fp = fopen("c.txt", "w+");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    fputs("hello world", fp);

    //复位文件流指针
    rewind(fp);

    char buf[1024]="";
    fgets(buf, sizeof(buf), fp);
    printf("buf=%s\n",buf);
    
    fclose(fp);
}

2、ftell 测文件读写位置距文件开始有多少个字节

long ftell(FILE *stream);
void test01(){
    FILE *fp = NULL;
    fp = fopen("c.txt", "w+");
    if(fp == NULL){
        perror("fopen");
        return;
    }

    fputs("hello world", fp);

    int len = 0;
    len = ftell(fp);
    printf("len = %d\n", len);

    fclose(fp);
}

int main(int argc, char const *argv[])
{
    test01();
    return 0;
}

3、fseek 定位位置指针(读写位置)

int fseek(FILE *stream, long offset, int whence)

案例1:将文件流指针 定位到文件的尾部

fseek(fp, 0, 2);

案例2:将文件数据 一次性读取到内存

#include <stdlib.h>
#include <string.h>
void test02()
{
    FILE *fp = NULL;
    fp = fopen("a.txt", "r");
    if(fp == NULL)
    {
        perror("fopen");
        return;
    }

    //获取文件总大小
    fseek(fp, 0, 2);//将文件流指针 定位到文件尾部
    long len = ftell(fp);//获取文件的大小
    rewind(fp);//复位文件流指针(方便后续读取文件数据)
    printf("len = %ld\n", len);
    //根据文件总大小申请空间
    unsigned char *data = NULL;
    data = (unsigned char *)calloc(1, len+1);
    fread(data, len, 1, fp);

    printf("%s\n", data);

    free(data);
    fclose(fp);
}

综合案例:文件加密器

详细设计API设计参考

1、从键盘获取源文件和目的文件名字

/**************************************************************************/
//函数功能:获取 目的文件和源文件的名字
//参数: src_file_name:源文件名字字符数组首地址。
// dest_file_name:目的文件的名字字符数组首地址
/**************************************************************************/
void get_file_name(char * dest_file_name,char * src_file_name)

2、从文件中读出内容

/**************************************************************************/
//函数功能:读出文件内容
//参数:file_length:整型指针,此地址中保存文件字节数。
// src_file_name:文件名字,从此文件中读取内容。
// 返回值:读出字符串的首地址
// 在此函数中测文件的大小,并malloc空间,再把文件内容读出返回,读出字符数组的首地址
/**************************************************************************/
char * read_src_file(unsigned long int *file_length,char *src_file_name)

3、字符数组加密

/**************************************************************************/
//函数功能:加密字符串
//参数:
//          src_file_text:要加密的字符串。 length:字符串的长度 
//          password: 加密密码
// 返回值: 加密后的字符串的首地址
// 加密原理字符数组中每个元素加上password
/**************************************************************************/
char * file_text_encrypt(char * src_file_text,unsigned long int length,unsigned int password)

4、解密字符串

/**************************************************************************/
//函数功能:解密字符串
//参数:
//          src_file_text:要解密的字符串。 length:字符串的长度 
//          password: 解密密码
// 返回值: 解密后的字符串的首地址
//思想;把数组中的每个元素减去password 给自己赋值。
/**************************************************************************/
char * file_text_decrypt(char * src_file_text,unsigned long int length,unsigned int password)

5、保存文件

/**************************************************************************/
//函数功能:将字符串保存到目的文件中
//参数:
//          text:要保存的字符串首地址   
//          file_name :目的文件的名字
//          length:字符串的长度
//思想:传入字符数组的首地址和数组的大小及保存后的文件的名字,即可保存数组到文件中
/**************************************************************************/
void save_file(char* text,unsigned long int length,char * file_name)

6、帮助信息

/**************************************************************************/
//
//          函数功能:打印帮助信息
//
//
/**************************************************************************/
void print_help()
{
            printf("********1:加密文件***********\n");
            printf("********2:解密文件***********\n");
            printf("********3:退出程序***********\n");
}

废话不多说了上程序(完全注释):

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/**************************************************************************/
//函数功能:获取 目的文件和源文件的名字
//参数: src_file_name:源文件名字字符数组首地址。
// dest_file_name:目的文件的名字字符数组首地址
/**************************************************************************/
void get_file_name(char * dest_file_name,char * src_file_name)
{
    printf("请输入你的原文件名称(30个字符):");                              //打印提示信息
    scanf("%s",src_file_name);                                            //输入源文件名src_file_name
    printf("请输入你的目标文件名称(30个字符):");                            //打印提示信息
    scanf("%s",dest_file_name);                                           //输入目的文件名dest_file_name
    return;
}

/**************************************************************************/
//函数功能:读出文件内容
//参数:file_length:整型指针,此地址中保存文件字节数。
// src_file_name:文件名字,从此文件中读取内容。
// 返回值:读出字符串的首地址
// 在此函数中测文件的大小,并malloc空间,再把文件内容读出返回,读出字符数组的首地址
/**************************************************************************/
char * read_src_file(unsigned long int *file_length,char *src_file_name)
{
    FILE *fp = fopen(src_file_name,"r");                                  //打开名叫src_file_name的源文件,文件指针给fp
    if(fp == NULL)                                                        //判断文件是否开启成功
    {
        printf("打开 %s 失败\n",src_file_name);                            //打印打开失败信息
        return NULL;                                                      //返回
    }

    fseek(fp,0,SEEK_END);                                                 //将流指针指向最后一个字符
    *file_length = ftell(fp);                                             //计算偏移长度(字节长度),返回给file_length
    rewind(fp);                                                           //重置流指针

    char *buf = (char *)calloc(1,*file_length+1);                         //申请对空间,存放文件内容
    fread(buf, *file_length, 1, fp);                                      //将文件全部内容拷贝到buf指向的空间

    fclose(fp);                                                           //关闭文件
    return buf;                                                           //返回堆空间地址
}

/**************************************************************************/
//函数功能:加密字符串
//参数:
//          src_file_text:要加密的字符串。 length:字符串的长度 
//          password: 加密密码
// 返回值: 加密后的字符串的首地址
// 加密原理字符数组中每个元素加上password
/**************************************************************************/
char * file_text_encrypt(char * src_file_text,unsigned long int length,unsigned int password)   
{
    int n = 0;                                                          //用于for循环遍历
    for(n = 0; n<length; n++)                                           //for循环遍历所有字符
    {
        *(src_file_text+n) += password;                                 //为字符加密
    }
    return src_file_text;                                               //返回src_file_text
}

/**************************************************************************/
//函数功能:解密字符串
//参数:
//          src_file_text:要解密的字符串。 length:字符串的长度 
//          password: 解密密码
// 返回值: 解密后的字符串的首地址
//思想;把数组中的每个元素减去password 给自己赋值。
/**************************************************************************/
char * file_text_decrypt(char * src_file_text,unsigned long int length,unsigned int password)
{
    int n = 0;                                                          //用于for循环遍历
    for(n = 0; n<length; n++)                                           //for循环遍历所有字符
    {
        *(src_file_text+n) -= password;                                 //为字符解密
    }
    return src_file_text;                                               //返回src_file_text
}

/**************************************************************************/
//函数功能:将字符串保存到目的文件中
//参数:
//          text:要保存的字符串首地址   
//          file_name :目的文件的名字
//          length:字符串的长度
//思想:传入字符数组的首地址和数组的大小及保存后的文件的名字,即可保存数组到文件中
/**************************************************************************/
void save_file(char* text,unsigned long int length,char * file_name)
{
    FILE *fp = fopen(file_name,"w");                                    //打开名叫file_name的源文件,文件指针给fp
    if(fp == NULL)                                                      //判断打开是否成功
    {
        printf("打开 %s 失败\n",file_name);                             //打印失败提示
        return;                                                         //返回
    }

    fwrite(text, length, 1, fp);                                      //将text内容写入文件

    fclose(fp);                                                         //关闭文件
    return;
}

/**************************************************************************/
//
//          函数功能:打印帮助信息
//
//
/**************************************************************************/
void print_help()
{
    printf("********1:加密文件***********\n");
    printf("********2:解密文件***********\n");
    printf("********3:退出程序***********\n");
}

int main(int argc, char const *argv[])
{
    char dest_file_name[30] = "", src_file_name[30] = "";                //存放源文件名和目标文件名
    char order = '\0';                                                   //存放指令
    char *src_file_text = NULL;                                          //创建一个字符指针准备接收堆空间地址
    unsigned long int length = 0;                                        //记录字符串长度
    unsigned int password = 0;                                           //用于存放密码值
    while(1)                                                             //死循环
    {
        print_help();                                                    //打印提示信息
        scanf("%c",&order);                                              //接收指令字符
        getchar();                                                       //接收输入字符后面的\n
        switch (order)                                                   //判断指令
        {
            case '1':                                                    //加密指令
                get_file_name(dest_file_name, src_file_name);            //输入源文件名和目标文件名
                src_file_text = read_src_file(&length,src_file_name);    //读取src_file_name文件中的全部内容放至申请到的堆区空间,返回空间地址到src_file_text

                printf("请输入你的密码:");                               //打印提示信息
                scanf("%d",&password);                                   //输入密码值保存在password中
                getchar();                                               //接收输入字符后面的\n

                src_file_text = file_text_encrypt(src_file_text, length, password); //进行字符串加密,并将字符串地址返回
                save_file(src_file_text, length, dest_file_name);        //将加密的字符串,保存到dest_file_name文件中
                if(src_file_text != NULL)
                {
                    free(src_file_text);                                     //堆区空间释放
                    src_file_text = NULL;
                }
                break;                                                   //跳出
            case '2':
                get_file_name(dest_file_name, src_file_name);            //输入源文件名和目标文件名
                src_file_text = read_src_file(&length,src_file_name);    //读取src_file_name文件中的全部内容放至申请到的堆区空间,返回空间地址到src_file_text

                printf("请输入你的密码:");                                //输入解密密码
                scanf("%d",&password);                                   //输入密码值保存在password中
                getchar();                                               //接收输入字符后面的\n

                src_file_text = file_text_decrypt(src_file_text, length, password); //进行字符串解密,并将字符串地址返回
                save_file(src_file_text, length, dest_file_name);        //将解密的字符串,保存到dest_file_name文件中
                if(src_file_text != NULL)
                {
                    free(src_file_text);                                     //堆区空间释放
                    src_file_text = NULL;
                }
                break;
            case '3':
                exit(-1);                                                //退出
                break;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值