C语言文件操作

在程序运行时所有对数据的运算结果都是在内存中,程序一旦退出后所有的结果都将丢失。为了存储程序运行的结果,都会将数据持久化到磁盘上,当程序再次启动就可以读取磁盘上存储的数据继续处理。
磁盘上的数据都是以文件的形式存在的。在C语言中,提供了标准的文件操作函数实现文件的读取和写入。
在C语言中操作文件一般分为三步:

  1. 打开文件
  2. 读取或写入文件
  3. 关闭文件

下面总结一下这三步中涉及到的函数以及相关的关键字。

一、打开文件

打开文件通过函数 fopen() 。函数原型是:

FILE * fopen(const char * _Filename, const char * _Mode);

函数两个参数:第一个参数是文件路径,第二个参数是文件打开模式。函数返回值是一个文件指针。打开模式有下面几种

打开模式模式描述
r只读模式:文件不存在则打开失败;成功打开文件后文件指针位于文件开头;可以从文件任意位置读取内容
w只写模式:文件不存在创建文件,文件已经存在清空文件内容;成功打开文件后文件指针位于文件开头;可以向文件中任意位置写入内容,写入时会覆盖原有位置的内容
a追加写模式:文件不存在创建文件,文件已存在不清空文件内容;成功打开文件后文件指针位于文件结尾;向文件写入内容时追加在文件尾部
rb操作二进制文件,模式特性与 r 相同
wb操作二进制文件,模式特性与 w 相同
ab操作二进制文件,模式特性与 a 相同

上面这些只能以只读或只写模式打开文件,下面这些可以同时支持读和写的方式打开文件:

打开模式模式描述
r+以读写模式(既可读取也可以写入)打开文件,文件不存在打开失败;成功打开文件后文件指针位于文件开头;打开文件后不会清空文件原有内容;读取或写入都可以在文件的任意位置,在写入内容时,会覆盖原有位置的内容
w+以读写模式(既可读取也可以写入)打开文件,文件不存在则新建文件;成功打开文件后文件指针位于文件开头;打开文件后会清空文件原有内容;读取或写入都可以在文件的任意位置,在写入内容时,会覆盖原有位置的内容
a+以读写模式(既可读取也可以写入)打开文件,文件不存在则新建文件;成功打开文件后文件指针位于文件结尾;打开文件后不会清空文件原有内容;读取内容时可以在文件的任意位置,在写入内容时会追加在文件尾部
r+b / rb+操作二进制文件,模式特性与 r+ 相同
w+b / wb+操作二进制文件,模式特性与 w+ 相同
a+b / ab+操作二进制文件,模式特性与 a+ 相同

比如以只读模式打开文件:

FILE * file = fopen("E:\\demo.txt", "r");

二、读文件或写文件

读取文件有四个函数:fgetc()、fgets()、fread()、fscanf();写文件也对应有四个函数:fputc()、fputs()、fwrite()、fprintf()。观察函数原型就知道,每一种读取文件的方式都对应一种类似的写入方式。下面分别说一下各个函数使用方式,所有的示例程序都是操作文本文件的,如果将模式改为带b,就完全适用于操作二进制文件:

1、fgetc : 一次读取一个字符

函数原型如下:

int fgetc(FILE *_File);

函数参数是打开的文件指针,函数返回值是读取到的字符:

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "r");

    // 读取文件内容
    int c;
    while((c = fgetc(file)) >= 0) {
        printf("%c", c);
    }
    printf("\n");

    // 关闭文件
    fclose(file);

    return 0;
}
2、fgets : 一次读取多个字符,将读取结果放入字符数组中

它从文件指针指向的位置开始读取,直到遇到换行符、文件结束或已读取指定-1个字符。它将读取的字符串包括换行符保存在字符数组中,并返回字符数组的指针。函数的返回值用于判断函数是否正常执行:如果返回 NULL,则表示发生错误或者读取到文件末尾;如果返回非 NULL,则表示读取成功。

函数原型如下:

char * fgets(char * _Buf, int _MaxCount, FILE * _File);

函数三个参数:第一个参数是字符数组,第二个参数是每次读取最大字符数量,第三个参数是文件指针。

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "r");

    // 读取文件内容
    char str[4] = { 0 };
    int len = sizeof(str);
    while (fgets(str, len, file) != NULL) {
        printf("%s", str);
    }
    printf("\n");

    // 关闭文件
    fclose(file);

    return 0;
}
3、fread : 一次读取文件指定长度内容到数组中

它可以读取文本文件也可以读取二进制文件。函数原型如下:

size_t fread(void * _DstBuf, size_t _ElementSize, size_t _Count, FILE * _File);

函数四个参数:第一个参数是接收数据的数组,第二个参数是数组中每个元素占用的字节,第三个参数是一次读取数据的最大数量,一般为接收数据数组的长度,第四个参数是文件指针。函数返回值是这次读取的字节数

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "r");

    // 读取文件内容
    char str[4] = { 0 };
    size_t eleSize = sizeof(char);
    size_t len = sizeof(str);
    size_t cnt;
    while ((cnt = fread(str, eleSize, len, file)) != 0) {
        for (int i = 0; i < cnt; ++i) {
            printf("%c", str[i]);
        }
    }
    printf("\n");

    // 关闭文件
    fclose(file);

    return 0;
}
4、fscanf:按照指定格式读取文件内容

该函数与scanf函数类似,只是它是从文件接收数据,函数原型如下:

int fscanf(FILE *__stream, const char *__format, ...);

与scanf函数原型:

int scanf(const char *__format, ...);

比较,多了一个文件指针参数,其他参数一致:

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "r");

    // 读取文件内容
    char str[64];
    fscanf(file, "%s", str);
    printf("%s\n", str);

    // 关闭文件
    fclose(file);

    return 0;
}
5、fputc:一次写一个字符

函数原型:

int fputc(int _Ch, FILE *_File);

函数第一个参数是写入的字符,第二个参数是函数指针;函数返回值是写入的字符。

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "w+");

    // 写内容到文件
    fputc('H', file);
    fputc('E', file);
    fputc('L', file);
    fputc('L', file);
    fputc('O', file);

    // 重新定位到文件开始
    rewind(file);
    // 读取文件内容
    char str[8];
    fgets(str, sizeof(str), file);
    printf("%s\n", str);

    // 关闭文件
    fclose(file);

    return 0;
}
6、fputs:一次写一个字符串到文件

函数原型:

int fputs(const char * _Str, FILE * _File);

函数的第一个参数是要写入的字符串,第二个参数是文件指针。函数返回值表示写入结果,如果写入成功返回一个非负数;如果发生写入错误,则返回 EOF,并设置 errno 以指示错误。EOF常被定义为-1。

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "w+");

    // 写内容到文件
    int rs = fputs("hello,world!", file);
    printf("%d\n", rs);

    // 重新定位到文件开始
    rewind(file);
    // 读取文件内容
    char str[16];
    fgets(str, sizeof(str), file);
    printf("%s\n", str);

    // 关闭文件
    fclose(file);

    return 0;
}
7、fwrite:一次写一批数据到文件

函数原型:

size_t fwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File);

第一个参数写入数据的指针,第二个参数是每个元素占用的字节,第三个参数是要写入元素个数,第四个参数是文件指针。函数的返回值是写入后的指针位置:

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "w+");

    // 写内容到文件
    char data[] = "hello,world!";
    size_t rs = fwrite(data, sizeof(char), sizeof(data), file);
    printf("%zu\n", rs);

    // 重新定位到文件开始
    rewind(file);
    // 读取文件内容
    char str[16];
    fgets(str, sizeof(str), file);
    printf("%s\n", str);

    // 关闭文件
    fclose(file);

    return 0;
}
8、fprintf:输出指定格式数据到文件中

函数原型:

int fprintf (FILE * __stream, const char *__format, ...);

与printf用法相似,函数输出结果到文件中,函数返回值是写入的字节数:

#include <stdio.h>

int main() {
    // 打开文件
    FILE * file = fopen("E:\\demo.txt", "w+");

    // 写内容到文件
    int rs = fprintf(file, "%s", "hello,world!");
    printf("%d\n", rs);

    // 重新定位到文件开始
    rewind(file);
    // 读取文件内容
    char str[16];
    fgets(str, sizeof(str), file);
    printf("%s\n", str);

    // 关闭文件
    fclose(file);

    return 0;
}

三、关闭文件

文件操作完成后要及时关闭,减少不必要的问题发生。关闭文件函数原型是:

int fclose(FILE * _File);

函数只需要一个参数文件指针,当 fclose 函数成功关闭文件时,它返回 0。如果发生错误,它将返回 EOF 并设置 errno。

四、删除文件

删除文件有两个函数remove和unlink,它们都可以实现文件删除功能。如果删除成功,remove函数返回0;如果删除失败,返回非零值。

#include <stdio.h>

int main() {
    // 删除文件
    int rs1 = remove("E:\\redis-7.2.5.tar.gz");
    printf("%d\n", rs1);
    int rs2 = unlink("E:\\redis-7.2.5-1.tar.gz");
    printf("%d\n", rs2);

    return 0;
}

请添加图片描述

五、获取文件大小和时间

获取文件大小是通过移动指向文件位置的指针到文件结尾,再获取指向位置来实现的:

#include <stdio.h>

int main() {
    FILE * file = fopen("E:\\redis-7.2.5.tar.gz", "rb");

    // 获取文件大小
    fseek(file, 0, SEEK_END);   // 定位到文件末尾
    long size = ftell(file);    // 获取文件大小
    printf("file size : %ld\n", size);

    // 重新定位到文件开头
    rewind(file);

    // 关闭文件
    fclose(file);

    return 0;
}

请添加图片描述

c语言中获取文件的时间是通过 stat 结构体和 stat() 函数实现的:

#include <stdio.h>
#include <sys/stat.h>
#include <time.h>

int main() {
    char file_name[] = "E:\\redis-7.2.5.tar.gz";

    struct stat file_stat;
    if (stat(file_name, &file_stat) == 0) {
        printf("file create time : %s", ctime(&file_stat.st_ctime));
        printf("file modify time : %s", ctime(&file_stat.st_mtime));
        printf("file access time : %s", ctime(&file_stat.st_atime));
    }

    return 0;
}

请添加图片描述

以上就是C语言有关文件操作的常用函数。下面示例如何使用上面的函数完成文件复制:

#include <stdio.h>

// C语言中没有定义字节类型,而char刚好占用一个字节,可以使用 unsigned char 表示字节类型
typedef unsigned char byte;

int copy_file(const char * src_path, const char * dest_path) {
    // 打开文件
    FILE * src_file = fopen(src_path, "rb");
    if (src_file == NULL) {
        printf("source file open fail!");
        return -1;
    }
    FILE * dest_file = fopen(dest_path, "wb");
    if (dest_file == NULL) {
        printf("target file open fail!");
        fclose(src_file);
        return -1;
    }
    // 写内容到文件
    byte bytes[1024];
    size_t ele_size = sizeof(byte);
    size_t buff_size = sizeof(bytes);
    size_t len = 0;     // 读取到文件内容字节数
    while ((len = fread(bytes, ele_size, buff_size, src_file)) > 0) {
        fwrite(bytes, ele_size, len, dest_file);
    }
    // 关闭文件
    fclose(src_file);
    fclose(dest_file);

    // 成功返回1
    return 1;
}

int main() {
    copy_file("E:\\redis-7.2.5.tar.gz", "E:\\cp-redis-7.2.5.tar.gz");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值