C语言:文件操作

为什么使用文件

在之前的通讯录程序中,我们介绍了如何使用文件来实现数据的持久化。然而,我们只是创建了储存功能,但只限于程序运行时。在程序退出以后,数据就不存在了。为了解决这个问题,我们通常会将数据存储到磁盘文件或数据库中。

使用文件我们可以将数据存放到电脑硬盘上,做到数据持久化

什么是文件

文件是指在磁盘或其他存储媒体上存储数据的一种数据结构。在程序设计中有两种文件:程序文件和数据文件。

程序文件

包括源程序(后缀位.c),目标文件(后缀为.obj),可执行文件(后缀为.exe)。

数据文件

文件的内容不一定是程序,而是程序运行时读写的数据。

文件名

文件名包括了三个部分:文件路径+文件名主干+文件后缀

eg:c:\code\test.txt#

文件的打开和关闭

文件指针

缓冲文件系统中关键概念是文件类型指针 ,简称文件指针。

每次被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件名,文件状态和文件的当前位置),这些信息保存在一个结构体变量中,该结构体变量由系统声明,取名:FILE。

在不同的编译环境下,FILE包含的内容大同小异。

每打开一个文件,系统会根据文件情况自动创建一个FILE,并填充其中信息

对一个程序员来说,一般通过FILE的指针来维护FILE结构变量。

文件的打开和关闭

文件在读写前应先打开文件,结束后应关闭文件。

在编写程序时,打开文件时会返回一个FILE的指针指向改文件,建立了指针与文件的关系。
ANIC规定用
fopen 打开文件 fclose*关闭文件

fopen

FILE * fopen(const charfilename,const char mode)

filename:这是一个字符串,包含了您想要打开的文件的路径。这个路径可以是相对路径或绝对路径。

相对路径:相对路径(Relative Path)是相对于当前工作目录(或者当前文件的位置)的路径。它不包含从根目录(如 Unix 系统中的 /,Windows 系统中的 C:\)开始的全部信息,而是从当前目录开始到目标文件或目录的路径。

例如,如果您的当前工作目录是 /home/user/documents,那么相对路径 subfolder/file.txt 指的是 /home/user/documents/subfolder/file.txt。
绝对路径 :绝对路径(Absolute Path)是一个完整的文件系统路径,它从文件系统的根目录开始,指定了文件或目录在文件系统中的确切位置。无论当前工作目录在哪里,绝对路径都能正确地定位到目标文件或目录。
mode:fopen 函数可以使用多种模式来打开文件。下面是所有有效的模式字符串列表:

"r": 打开文件用于读取。如果文件不存在,fopen 返回 NULL。

"w": 打开文件用于写入。如果文件存在,则清空内容;如果文件不存在,则创建新文件。

"a": 打开文件用于追加。如果文件存在,数据将被追加到文件末尾;如果文件不存在,则创建新文件。

"r+": 打开文件用于读写。如果文件不存在,fopen 返回 NULL。

"w+": 打开文件用于读写。如果文件存在,则清空内容;如果文件不存在,则创建新文件。

"a+": 打开文件用于读取和追加。如果文件存在,数据将被追加到文件末尾;如果文件不存在,则创建新文件。

"rb": 打开二进制文件用于读取。

"wb": 打开二进制文件用于写入。

"ab": 打开二进制文件用于追加。

"rb+": 打开二进制文件用于读写。

"wb+": 打开二进制文件用于读写。

"ab+": 打开二进制文件用于读取和追加。

此外,还可以在模式字符串中包含以下特殊字符:

"t": 文本模式(默认值)。

"b": 二进制模式。

"+": 同时进行读写操作。

eg:

FILE* pf=fopen("data.txt","r");

尝试打开名为 data.txt 的文件,以便进行读取操作。如果文件存在且打开成功,fopen 函数将返回一个指向 FILE 对象的指针,该指针可以用来 subsequent I/O 操作。如果文件不存在或者由于其他原因无法打开,fopen 函数将返回 NULL。

fclose

int fclose(FILE *stream);
参数说明:

stream: 这是一个 FILE 类型的指针,它指向之前通过 fopen 函数打开的文件。
函数返回值:

如果关闭成功,fclose 函数返回 0。

如果发生错误,fclose 函数返回 EOF(-1 的宏定义)。
功能说明:

当您完成文件的读写操作后,应该使用 fclose 函数来关闭文件。这不仅会释放文件描述符和相关资源,还会确保所有的缓冲区内容都被刷新到文件中,从而确保数据的持久保存。

文件的顺序读写

函数名称 作用 原型 返回值 说明
fgetc 从文件中读取一个字符 int fgetc(FILE *stream); 读取的字符或 EOF 每次调用读取文件的一个字符
fputc 将一个字符写入文件 int fputc(int c, FILE *stream); 写入的字符或 EOF 每次调用写入文件的一个字符
fgets 从文件中读取一行文本 char *fgets(char *str, int n, FILE *stream); 读取的文本或 NULL 每次调用读取文件的一行文本
fputs 将一行文本写入文件 int fputs(const char *str, FILE *stream); 写入的字节数或 EOF 每次调用写入文件的一行文本
fscanf 读取文件并转换成变量 int fscanf(FILE *stream, const char *format, ...); 读取并转换的输入项数 根据格式字符串读取文件并转换成变量
fprintf 将变量格式化后写入文件 int fprintf(FILE *stream, const char *format, ...); 写入的字节数 根据格式字符串将变量写入文件
fread 从文件中读取数据 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 读取的字节数或 EOF 每次调用读取指定数量的字节
fwrite 将数据写入文件 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); 写入的字节数 每次调用写入指定数量的字节
eg 1: 使用 fgetc 读取文件中的一个字符
c 复制代码
#include <stdio.h>
int main() {
    FILE *fp;
    char ch;
    fp = fopen("data.txt", "r"); // 打开文件用于读取
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    ch = fgetc(fp); // 读取文件中的第一个字符
    printf("Read character: %c\n", ch);
    fclose(fp); // 关闭文件
    return 0;
}

eg 2: 使用 fgets 读取文件中的一行文本

c 复制代码
#include <stdio.h>
int main() {
    FILE *fp;
    char buffer[100];
    fp = fopen("data.txt", "r"); // 打开文件用于读取
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    fgets(buffer, 100, fp); // 读取文件中的一行文本
    printf("Read line: %s\n", buffer);
    fclose(fp); // 关闭文件
    return 0;
}

eg 3: 使用 fwrite 写入数据到文件

c 复制代码
#include <stdio.h>
int main() {
    FILE *fp;
    int data[] = {1, 2, 3, 4, 5};
    size_t bytes_written;
    fp = fopen("data.bin", "wb"); // 打开文件用于写入
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    bytes_written = fwrite(data, sizeof(int), 5, fp); // 写入数据到文件
    printf("Written bytes: %zu\n", bytes_written);
    fclose(fp); // 关闭文件
    return 0;
}

每个例子都包含了打开文件、执行读写操作和关闭文件的步骤。这些例子展示了如何在 C 语言中使用这些基本的文件操作函数。

文件的随机读写

文件的随机读写是指可以读取或写入文件中的任意位置的数据,而不必按照文件的顺序进行。随机读写函数允许你直接跳转到文件中的特定位置,读取或写入一个或多个字节。以下是一些常用的文件随机读写函数。

在 C 语言中,文件的随机读写是指可以读取或写入文件中的任意位置的数据,而不必按照文件的顺序进行。随机读写函数允许你直接跳转到文件中的特定位置,读取或写入一个或多个字节。以下是一些常用的文件随机读写函数:

文件随机读取函数

  1. fseek

    c 复制代码
    int fseek(FILE *stream, long int offset, int whence);

    fseek 函数用于设置文件的读/写位置。stream 参数是指向 FILE 对象的指针,offset 是一个长整型数,表示从 whence 指定的位置开始的偏移量。whence 参数可以是 SEEK_SET(文件开头)、SEEK_CUR(当前位置)或 SEEK_END(文件末尾)。函数返回 0 表示成功,或者返回 -1 表示失败。

  2. ftell

    c 复制代码
    long int ftell(FILE *stream);

    ftell 函数用于获取当前文件的读/写位置。函数返回当前位置相对于文件开头的偏移量,如果出错,返回 -1

  3. fgetc(用于随机读取)

    c 复制代码
    int fgetc(FILE *stream);

    fgetc 函数用于读取文件的一个字符。为了实现随机读取,你首先需要使用 fseek 函数将文件指针移动到想要读取的位置。

文件随机写入函数

  1. fputc(用于随机写入)

    c 复制代码
    int fputc(int c, FILE *stream);

    fputc 函数用于写入文件的一个字符。为了实现随机写入,你首先需要使用 fseek 函数将文件指针移动到想要写入的位置。

  2. fwrite

    c 复制代码
    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

    fwrite 函数用于向文件中写入数据。为了实现随机写入,你首先需要使用 fseek 函数将文件指针移动到想要写入的位置。

示例代码

以下是一个简单的示例,展示了如何使用 fseekfwrite 函数进行文件的随机写入:

c 复制代码
#include <stdio.h>
int main() {
    FILE *fp;
    int data[] = {1, 2, 3, 4, 5};
    size_t bytes_written;
    fp = fopen("data.bin", "w+b"); // 打开文件用于写入和读取
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    // 将文件指针移动到文件末尾
    fseek(fp, 0, SEEK_END);
    // 写入数据到文件末尾
    bytes_written = fwrite(data, sizeof(int), 5, fp);
    printf("Written bytes: %zu\n", bytes_written);
    // 关闭文件
    fclose(fp);
    return 0;
}

在上面的示例中,我们使用了 fseek 函数将文件指针移动到文件末尾,然后使用 fwrite 函数向文件末尾写入数据。这样可以实现文件的随机写入操作。

rewind 函数

用于将文件指针重新定位到文件的开始位置。这个函数非常有用,当你想要从头开始重新读取一个文件时,而不想从头开始逐字节移动文件指针。以下是 rewind 函数的原型:

c 复制代码
void rewind(FILE *stream);

rewind 函数接受一个指向 FILE 对象的指针 stream,表示要重置的文件流。调用 rewind 函数后,文件指针将移动到文件的开头,就像文件刚刚被打开一样。

下面是一个使用 rewind 函数的示例:

c 复制代码
#include <stdio.h>
int main() {
    FILE *fp;
    int ch;
    fp = fopen("data.txt", "r"); // 打开文件用于读取
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    // 读取文件的一个字符
    ch = fgetc(fp);
    printf("Read character: %c\n", ch);
    // 将文件指针重新定位到文件开始位置
    rewind(fp);
    // 重新读取文件的一个字符
    ch = fgetc(fp);
    printf("Rewinded and read character: %c\n", ch);
    // 关闭文件
    fclose(fp);
    return 0;
}

在上述示例中,我们首先读取了文件 data.txt 的一个字符,然后调用了 rewind 函数将文件指针重新定位到文件的开头。之后,我们再次读取了文件的一个字符。由于 rewind 函数的作用,第二次读取的是文件开头的同一个字符。
rewind 函数通常用于数据处理任务,比如当你需要对文件进行多次读取操作,并且每次都需要从文件开始处读取时,使用 rewind 函数可以简化代码,避免手动移动文件指针的复杂性。

文件读取结束的判定

在 C 语言中,文件操作是编程中的一个常见任务。当我们读取文件时,我们需要一种方法来确定何时我们已经到达文件的末尾。这里,我们要讨论的是如何使用 feof 函数来帮助我们判断文件是否已经读取完毕。

首先,我们需要明确一点:feof 函数并不直接告诉我们文件是否结束,而是告诉我们文件指针是否已经到达文件末尾。这意味着,即使 feof 返回 1,文件也可能还有数据,只是文件指针已经超出了数据区域。因此,我们不能仅仅依赖 feof 的返回值来判断文件是否结束。

正确的方法是,在每次读取操作之后,检查读取函数的返回值。例如,当我们使用 fgetcfgets 读取文件时,如果文件已经读取完毕,fgetc 会返回 EOF(End Of File),而 fgets 会返回一个空字符串(\0)。这样,我们就可以确定文件是否已经读取完毕。

下面是一个示例,展示了如何正确使用 fgetcfeof

c 复制代码
#include <stdio.h>
int main() {
    FILE *fp;
    int ch;
    fp = fopen("data.txt", "r"); // 打开文件用于读取
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    // 逐字符读取文件
    while ((ch = fgetc(fp)) != EOF) {
        printf("Read character: %c\n", ch);
    }
    // 检查是否到达文件末尾
    if (feof(fp)) {
        printf("Reached end of file due to EOF.\n");
    } else {
        printf("Did not reach end of file.\n");
    }
    // 关闭文件
    fclose(fp);
    return 0;
}

在这个示例中,我们使用 while 循环逐字符读取文件。每次 fgetc 函数读取一个字符后,我们检查返回值是否为 EOF。如果是,我们使用 feof 函数来确认是否已经到达文件末尾。如果 feof 返回 1,我们输出 "Reached end of file due to EOF.";如果返回 0,我们输出 "Did not reach end of file."。

这样,我们就通过正确的逻辑来判断文件是否读取结束,而不是直接依赖 feof 的返回值。这种方法可以确保我们在文件末尾正确地处理数据,而不会错误地认为文件中还有未读取的数据。

相关推荐
存储服务专家StorageExpert7 分钟前
DELL SC compellent存储的四种访问方式
运维·服务器·存储维护·emc存储
_GR7 分钟前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
凯子坚持 c9 分钟前
C语言复习概要(三)
c语言·开发语言
coderWangbuer16 分钟前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql
无限大.20 分钟前
c语言200例 067
java·c语言·开发语言
余炜yw22 分钟前
【Java序列化器】Java 中常用序列化器的探索与实践
java·开发语言
攸攸太上22 分钟前
JMeter学习
java·后端·学习·jmeter·微服务
无限大.23 分钟前
c语言实例
c语言·数据结构·算法
Kenny.志25 分钟前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
Death20026 分钟前
Qt 中的 QListWidget、QTreeWidget 和 QTableWidget:简化的数据展示控件
c语言·开发语言·c++·qt·c#