14_文件

文件

文件概述

文件分类(存储介质)

磁盘文件: 文件的数据 存放在磁盘上 (音视频, 图片文件, 文档文件)

设备文件: 通过系统将外部设备抽象文件

文件分类(存储方式)

任何磁盘文件 物理上都是二进制存储

逻辑上: 磁盘文件分为二进制文件, 文本文件

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

​ 二进制文件: 基于值编码的文件

image-20230905133746274

image-20230905133805370

image-20230905134816950

文件缓冲区

目的: 提高访问效率 提高磁盘使用寿命

image-20230905144304723

文件缓冲区的刷新方式

行刷新(遇到换行符 刷新)

//结果: 不会打印kjsdhfkksdjhnfkkdshn
int main(int argc, char const *argv[])
{
    printf("kjsdhfkksdjhnfkkdshn");
    while (1);
    return 0;
}
//结果: 会打印kjsdhfkksdjhnfkkdshn
int main(int argc, char const *argv[])
{
    printf("kjsdhfkksdjhnfkkdshn\n");
    while (1);
    return 0;
}

满刷新(缓冲区数据放满刷新)

image-20230905162107606

强制刷新(使用fflush 将缓存刷新)

fflush(stdout); //强制刷新

关闭刷新(关闭文件时, 将缓冲区数据 全部刷新)

image-20230905162307899

模拟时钟

image-20230905162548729

文件指针(重要)

所有操作文件的库函数 都需要借助文件指针 操作文件

image-20230905163523217

image-20230906081620623

在缓冲文件系统中,每个被使用的文件都要在内存中开辟一块FILE类型的区域,存放与操作文件相关的信息

image-20230906082001368

文件的API

文件操作步骤: 打开 读写 关闭

打开文件fopen

FILE *fopen(const char *pathname, const char *mode);
pathname: 文件路径
mode: 打开文件方式
    r w a + t b
    r: 只读方式打开 w: 只写方式打开 a: 追加方式打开
    +: 可读可写方式打开 t:文本文件方式打开(默认省略: r[t])
    b: 二进制方式打开(必须显示: rb)
组合:
	r/rb: 只读方式打开一个文本文件(不创建文件)
    w/wb: 写方式打开文件(文件不存在,创建一个, 文件存在,就删除再创建)
    r+/rb+: 可读可写方式打开文件(不创建新文件)
    a/ab: 添加方式打开文件, 即在末尾添加内容, 当文件不存在时, 创建文件用于写
    w+/wb+: 可读可写方式打开文件(文件不存在创建, 存在删除再创建)
    a+/ab+: 和a/ab一样只不过可读可写
返回值:
	成功: 打开的文件指针
    失败: NULL
函数说明:
	fopen函数打开一个已经存在的文件,并返回这个文件的文件指针(文件的标示)或者创建一个文件, 并打开此文件,然后返回文件的标示

关闭文件 fclose

int fclose(FILE *fp);
返回值:
	成功返回 0
    失败返回非0

image-20230906090238223

一次读写一个字符

一次写一个字符

int fputc(int c, FILE *stream);
说明: fputc将c的值写到stream代表的文件中
返回值:
	输出成功: 返回输出的字节值
    输出失败: 返回EOF(定义再stdio.h中的符号常量, 值为-1)

一次读一个字符

int fgetc(FILE *stream);
说明: fgetc从stream的文件中读取一个字节, 并返回
返回值:
	以t的方式: 读到文件结尾返回EOF
    以b的方式: 读到文件结尾, 使用feof判断结尾
rewind(fp); //指针位置重置
int main(int argc, char const *argv[])
{
    //写
    FILE *fp = NULL;
    fp = fopen("test.txt", "w+");
    if (fp == NULL)
    {
        ferror("error: fopen\n");
    }
    else
    {
        char *file_data = "hello world";
        while (*file_data != '\0')
        {
            fputc(*file_data, fp);
            file_data++;
        }
    }
    rewind(fp); //指针位置回到开头
    //读
    while (1)
    {
        char c = fgetc(fp);
        if (c == EOF)
        {
            break;
        }
        printf("%c", c);
    }
    printf("\n");
    fclose(fp);
    return 0;
}

一次读写一个字符串

一次写一个字符串

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

一次读一个字符串

char *fgets(char *s, int size, FILE *stream);
说明: 从stream的文件中读取字符, 碰到换行符或末尾停止读取, 或者读取 size-1 个字节停止读取, 在读取的内容后面加一个'\0', 作为字符串的结尾
返回值:
	成功返回目的字符串首地址, 即s
    失败返回NULL
int main(int argc, char const *argv[])
{
    FILE *fp = NULL;
    char *text = "hhhh text \n sdklfjl\n dsjkfli\n oirffujgo\n idsjfuio\n isdhfuio\nsdf ";
    fp = fopen("text.txt", "w+");
    char c = fputs(text, fp);
    if (c == EOF)
    {
        ferror("fputs error!");
    }
    rewind(fp);
    FILE *fp2 = NULL;
    fp2 = fopen("text2.txt", "w+");
    while (1)
    {
        char buf[128] = "";
        char *ret = fgets(buf, sizeof(buf), fp);
        if (ret == NULL)
        {
            break;
        }
        fputs(buf, fp2);
    }
    fclose(fp);
    fclose(fp2);
    return 0;
}

一次读写n块数据

块写

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
解释:
	ptr: 内存数据
    size: 数据大小
    nmemb: 数据数量
    stream: 文件
说明: 将ptr写到stream
返回值: 实际写入的块数
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值: 实际读到的块数, 不足一块 不计数

fread 读到的数据, 不便于查看

格式化读写

image-20230906190335294

格式化读写

fprintf(文件指针, 格式字符串, 输出列表)
fscanf(文件指针, 格式字符串, 输出列表)
typedef struct s_hero
{
    char name[16];
    int atk;
    int def;
} HERO;

int main(int argc, char const *argv[])
{
    HERO hero[] = {{"德玛西亚", 50, 80}, {"小法", 70, 30}, {"亚索", 80, 30}};
    FILE *fp = fopen("hero.txt", "w+");
    int n = sizeof(hero)/sizeof(hero[0]);
    for (int i = 0; i < n; i++)
    {
        fprintf(fp, "%s %d %d\n", hero[i].name, hero[i].atk, hero[i].def);
    }
    for (int i = 0; i < n; i++)
    {
        fscanf(fp, "%s %d %d", hero[i].name, hero[i].atk, hero[i].def);
    }
    for (int i = 0; i < n; i++)
    {
        printf("%s %d %d\n", hero[i].name, hero[i].atk, hero[i].def);
    }
    
    fclose(fp);
    return 0;
}

image-20230906192229589

文件的随机读写

文件默认是顺序读写: 读写才能移动流指针 用户不能修改

随机读写: 用户可以更改文件流指针的位置

引入案例

image-20230907083327683

随机读写的API

fseek rewind ftell

rewind复位文件流指针

void rewind(FILE *stream);

image-20230907083622028

ftell 返回文件流指针 距离文件首部的字节数

long ftell(FILE *stream);

image-20230907084123719

fseek 文件流指针定位

int fseek(FILE *stream, long offset, int whence);
解析:
	offset: 流指针的偏移量
		正数: 向右偏移(单位为字节数)
        负数: 向左偏移
	whence: 起始位置
    	SEEK_SET 0: 文件开头
        SEEK_CUR 1: 文件当前位置
        SEEK_END 2: 文件末尾

一次性读取文件数据

int main(int argc, char const *argv[])
{
    FILE *fp = fopen("c.txt", "r");
    if (fp == NULL)
    {
        ferror("fopen error!");
        return 0;
    }
    fseek(fp, 0, 2);
    long len = ftell(fp);
    printf("len = %ld\n", len);
    rewind(fp);
    unsigned char *text = (unsigned  char *) calloc(1, len+1);
    fread(text, len, 1, fp);
    printf("%s\n", text);
    printf("len = %d\n", strlen(text));
    fclose(fp);
    //释放堆区空间
    if (text != NULL)
    {
        free(text);
        text = NULL;
    }
    return 0;
}

文件加密器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
 * 文件加密
 */
int main(int argc, char const *argv[])
{
    int order = 0;
    char old_name[30] = "";
    char new_name[30] = "";
    unsigned int password = 0;
    unsigned char *buf = NULL;
    long len = 0;
    FILE *ofp = NULL;
    FILE *nfp = NULL;
    while (1)
    {
        printf("********1:加密文件********\n");
        printf("********2:解密文件********\n");
        printf("********3:退出程序********\n");
        printf("请输入指令: ");
        scanf("%d", &order);

        switch (order)
        {
        // 1 加密
        case 1:
            printf("请输入你的原文件名称(30个字符): ");
            scanf("%s", old_name);
            ofp = fopen(old_name, "r");
            if (ofp == NULL)
            {
                printf("没找到该文件!\n");
                break;
            }
            printf("请输入你的目的文件名称(30个字符): ");
            scanf("%s", new_name);
            nfp = fopen(new_name, "w");
            if (nfp == NULL)
            {
                printf("nfp fopen error!\n");
                break;
            }
            printf("please input your unsigned int passworld: ");
            scanf("%u", &password);
            fseek(ofp, 0, 2);
            len = ftell(ofp);
            rewind(ofp);
            buf = (unsigned char *)calloc(1, len + 1);
            fread(buf, len, 1, ofp);
            // 加密
            for (int i = 0; i < strlen(buf); i++)
            {
                buf[i] += password;
            }
            fwrite(buf, len, 1, nfp);
            printf("save success!\n");
            fclose(ofp);
            fclose(nfp);
            free(buf);
            break;
        // 解密
        case 2:
            printf("请输入你的原文件名称(30个字符): ");
            scanf("%s", old_name);
            ofp = fopen(old_name, "r");
            if (ofp == NULL)
            {
                printf("没找到该文件!\n");
                break;
            }
            printf("请输入你的目的文件名称(30个字符): ");
            scanf("%s", new_name);
            nfp = fopen(new_name, "w");
            if (nfp == NULL)
            {
                printf("nfp fopen error!\n");
                break;
            }
            printf("please input your unsigned int passworld: ");
            scanf("%u", &password);
            fseek(ofp, 0, 2);
            len = ftell(ofp);
            rewind(ofp);
            buf = (unsigned char *)calloc(1, len + 1);
            fread(buf, len, 1, ofp);
            // 解密
            for (int i = 0; i < strlen(buf); i++)
            {
                buf[i] -= password;
            }
            fwrite(buf, len, 1, nfp);
            printf("save success!\n");
            fclose(ofp);
            fclose(nfp);
            free(buf);
            break;
        case 3:
            return 0;

        default:
            printf("命令错误,请重新输入!\n");
            break;
        }
    }
    return 0;
}
posted @ 2023-09-07 15:23  爱吃冰激凌的黄某某  阅读(16)  评论(0编辑  收藏  举报