C语言如何读取txt文件中的字符串?

99ANYc3cd6
预计阅读时长 18 分钟
位置: 首页 C语言 正文

一个示例TXT文件

我们创建一个名为 data.txt 的文件,内容如下,我们将使用这个文件作为所有示例的输入。

c语言读取txt文件字符串
(图片来源网络,侵删)

data.txt 文件内容:

Hello, World!
This is the second line.
C programming is fun.
12345

使用 fgets() - 最常用、最安全的方法

fgets() 函数是读取文件行的最佳选择,因为它可以一次性读取一行文本,并且有内置的缓冲区大小限制,能有效防止缓冲区溢出。

函数原型

char *fgets(char *str, int n, FILE *stream);
  • str: 一个字符数组(缓冲区),用于存储读取到的字符串。
  • n: 要读取的最大字符数(包括结尾的 \0)。
  • stream: 文件指针(通过 fopen 获取)。
  • 返回值: 成功时返回 str,到达文件末尾或出错时返回 NULL

完整示例代码

#include <stdio.h>
#include <string.h> // 用于 strlen()
#define MAX_LINE_LENGTH 256 // 定义每行最大长度
int main() {
    // 1. 打开文件
    // "r" 表示以只读模式打开文本文件
    FILE *file = fopen("data.txt", "r");
    if (file == NULL) {
        perror("无法打开文件"); // perror会打印出具体的错误信息
        return 1; // 返回非零表示错误
    }
    char line[MAX_LINE_LENGTH]; // 创建一个缓冲区来存放每一行
    // 2. 循环读取文件
    // fgets会读取一行,包括换行符\n
    // 当fgets返回NULL时,表示文件已读完或发生错误
    while (fgets(line, sizeof(line), file) != NULL) {
        // 去掉行尾的换行符(如果存在)
        // 因为fgets会保留换行符,而我们通常不需要它
        size_t len = strlen(line);
        if (len > 0 && line[len - 1] == '\n') {
            line[len - 1] = '\0'; // 将换行符替换为字符串结束符
        }
        // 3. 处理读取到的字符串
        printf("读取到一行: %s\n", line);
    }
    // 4. 关闭文件
    fclose(file);
    return 0;
}

代码解释

  1. fopen("data.txt", "r"): 以只读模式("r")打开 data.txt 文件,如果文件不存在,fopen 会返回 NULL,所以必须检查。
  2. char line[MAX_LINE_LENGTH]: 定义一个足够大的字符数组作为缓冲区。sizeof(line) 会自动计算出数组的大小(这里是256)。
  3. while (fgets(...)): 这是一个非常经典的读取文件的循环。fgets 会尝试读取一行到 line 中,如果成功,它返回 line 的地址(非NULL),循环继续,当文件读完或出错时,它返回 NULL,循环终止。
  4. line[len - 1] = '\0': fgets 会保留行尾的换行符 \n,这通常不是我们想要的,所以手动检查并替换掉它,让字符串更“干净”。
  5. fclose(file): 文件操作完成后,必须关闭文件,释放系统资源。

使用 fscanf() - 按格式读取

fscanf() 函数可以根据指定的格式从文件中读取数据,它类似于 scanf(),只是输入源是文件而不是标准输入。

函数原型

int fscanf(FILE *stream, const char *format, ...);

完整示例代码

#include <stdio.h>
#define MAX_STRING_LENGTH 100
int main() {
    FILE *file = fopen("data.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }
    char str[MAX_STRING_LENGTH];
    // %s 表示读取一个字符串,遇到空白字符(空格、制表符、换行符)会停止
    // fscanf会自动在读取的字符串末尾添加'\0'
    while (fscanf(file, "%s", str) != EOF) {
        printf("读取到一个单词: %s\n", str);
    }
    fclose(file);
    return 0;
}

代码解释

  • fscanf(file, "%s", str) != EOF: fscanf 的返回值是成功匹配并赋值的字段数量,当到达文件末尾时,它会返回 EOF (End-Of-File)。
  • %s 的局限性: %s 会读取一个“单词”,即直到遇到空格、\t\n 为止,对于 data.txt 的第一行 "Hello, World!",它会先读取 "Hello,",然后读取 "World!",无法一次性读取整行。

fscanf 适合读取结构化的、由特定分隔符隔开的数据(如CSV文件),不适合读取包含空格的整行文本。

c语言读取txt文件字符串
(图片来源网络,侵删)

逐个字符读取 (fgetc()) - 最底层的方法

这种方法虽然不常用来读取“字符串”,但能帮助你理解文件读取的本质,它一次只读取一个字符,你需要自己将它们拼接成字符串。

完整示例代码

#include <stdio.h>
#include <stdlib.h> // 用于 malloc 和 free
int main() {
    FILE *file = fopen("data.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }
    // 动态分配内存来存储字符串,初始大小设为100
    size_t capacity = 100;
    char *str = (char *)malloc(capacity * sizeof(char));
    if (str == NULL) {
        perror("内存分配失败");
        fclose(file);
        return 1;
    }
    size_t length = 0;
    int c; // 必须是 int,因为 fgetc 返回的 EOF 是一个 int 值
    // 读取字符,直到文件末尾或遇到换行符
    while ((c = fgetc(file)) != EOF && c != '\n') {
        // 检查是否需要扩容
        if (length + 1 >= capacity) {
            capacity *= 2; // 容量翻倍
            char *temp = (char *)realloc(str, capacity);
            if (temp == NULL) {
                perror("内存重新分配失败");
                free(str);
                fclose(file);
                return 1;
            }
            str = temp;
        }
        str[length++] = (char)c;
    }
    // 添加字符串结束符
    str[length] = '\0';
    // 如果读取到了内容(length > 0),则打印
    if (length > 0) {
        printf("读取到一行(用fgetc拼接): %s\n", str);
    }
    // 释放内存
    free(str);
    fclose(file);
    return 0;
}

代码解释

  1. fgetc(file): 从文件中读取一个字符,返回 int 类型,如果到达文件末尾,返回 EOF
  2. 动态内存分配: 因为不知道一行会有多长,所以使用 malloc 动态分配内存,并在需要时用 realloc 扩展。
  3. 拼接字符串: 在循环中,将每个字符依次存入 str 数组,并更新长度 length
  4. str[length] = '\0': 手动添加字符串结束符,这是C语言字符串的必需步骤。
  5. free(str): 动态分配的内存,使用后必须手动释放,否则会造成内存泄漏。

这种方法非常灵活,可以处理任意长度的行,但代码复杂,容易出错。在绝大多数情况下,优先使用 fgets()


总结与对比

方法 优点 缺点 适用场景
fgets() 简单、安全、高效,有缓冲区限制,防止溢出 保留行尾的 \n 需要手动处理 读取文件行的首选方法,适用于99%的场景。
fscanf() 可以按指定格式(如数字、特定分隔符)读取数据 无法正确读取带空格的整行,格式匹配失败时行为复杂 读取结构化数据,如配置文件、CSV等。
fgetc() 最底层,控制力最强,可处理任意长度的行 代码复杂,需要手动管理内存和字符串拼接 需要精细控制读取过程,或处理非标准文本格式的特殊情况。

给初学者的建议:

直接学习和使用 fgets(),它是读取文本文件最标准、最安全、最方便的方式,掌握它,你就能解决绝大多数文件读取字符串的问题。

-- 展开阅读全文 --
头像
dede如何调用图片地址?
« 上一篇 03-07
dede模块管理为何不显示?
下一篇 » 03-07

相关文章

取消
微信二维码
支付宝二维码

目录[+]