【C语言】文件操作(二)

前言

在文件操作(一)中我们了解了文件及文件指针,还有文件的打开和关闭。在这篇博客我们学习顺序读写文件的几个函数。


文章目录

  • 一、文件的顺序读写
  • [1.1 顺序读写函数介绍](#1.1 顺序读写函数介绍)
    • [fgetc 字符输入函数](#fgetc 字符输入函数)
    • [fputc 字符输出函数](#fputc 字符输出函数)
    • [fgets 文本行输入函数](#fgets 文本行输入函数)
    • [fputs 文本行输出函数](#fputs 文本行输出函数)
    • [fread ---二进制输入 fwrite ---二进制输入](#fread —二进制输入 fwrite —二进制输入)
  • [1.2 比较一些函数](#1.2 比较一些函数)

一、文件的顺序读写

1.1 顺序读写函数介绍

函数名 功能 适用于
fgetc 字符输⼊函数 所有输⼊流
fputc 字符输出函数 所有输出流
fgets ⽂本⾏输⼊函数 所有输⼊流
fputs ⽂本⾏输出函数 所有输出流
fscanf 格式化输⼊函数 所有输⼊流
fprintf 格式化输出函数 所有输出流
fread ⼆进制输⼊ ⽂件
fwrite ⼆进制输出 ⽂件

fgetc 字符输入函数

c 复制代码
int fgetc(FILE *stream)
参数------stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。

返回值------该函数以无符号 char 强制转换为 int 的形式返回读取的字符(整数代表从文件流中读取的下一个字符的字符编码值),如果到达文件末尾或发生读错误,则返回 EOF。

实例:

c 复制代码
#include <stdio.h>

int main() {
    // 打开文件以供读取
    FILE *file = fopen("example.txt", "r");//"r"不会自动创建文件,需要我们自己在创建

    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int character;
    
    // 使用 fgetc 逐字符读取文件内容
    while ((character = fgetc(file)) != EOF) {
        // 打印读取的字符
        putchar(character);
    }

    // 关闭文件
    fclose(file);

    return 0;
}

创建文本文档:

运行结果:


fputc 字符输出函数

c 复制代码
int fputc(int char, FILE *stream)
参数------char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
      stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。

返回值------如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。

实例:

c 复制代码
#include <stdio.h>

int main() {
    // 打开文件以供写入
    FILE *file = fopen("output.txt", "w");//"w"如果没有output.txt文件,建⽴⼀个新的⽂件
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    // 要写入文件的字符
    char character = 'A';

    // 使用 fputc 将字符写入文件
    if (fputc(character, file) == EOF) {
        perror("写入文件时出错");
        return 1;
    }

    // 关闭文件
    fclose(file);

    return 0;
}

运行结果:


fgets 文本行输入函数

c 复制代码
char *fgets(char *str, int n, FILE *stream)
参数------str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
      n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
      stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

返回值------如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。如果发生错误,返回一个空指针。

实例:

c 复制代码
#include <stdio.h>

int main() {
    // 打开文件以供读取
    FILE* file = fopen("example.txt", "r");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    // 字符数组用于存储读取的文本行
    char buffer[13];

    // 使用 fgets 从文件中读取一行文本
    while (fgets(buffer, sizeof(buffer), file) != NULL) {
        // 打印读取的文本行
        printf("%s", buffer);
    } 

    // 关闭文件
    fclose(file);

    return 0;
}

创建文本文档:

运行结果:


fputs 文本行输出函数

c 复制代码
int fputs(const char *str, FILE *stream)
参数------str -- 这是一个数组,包含了要写入的以空字符终止的字符序列。
      stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。

返回值------该函数返回一个非负值,如果发生错误则返回 EOF。

实例:

c 复制代码
#include <stdio.h>

int main() {
    // 打开文件以供写入
    FILE *file = fopen("output.txt", "w");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    // 要写入文件的字符串
    const char *text = "Hello, World!";

    // 使用 fputs 将字符串写入文件
    if (fputs(text, file) == EOF) {
        perror("写入文件时出错");
        return 1;
    }

    // 关闭文件
    fclose(file);

    return 0;
}

运行结果:


fread ---二进制输入 fwrite ---二进制输入

c 复制代码
//fread
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
参数------ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
      size -- 这是要读取的每个元素的大小,以字节为单位。
      nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
      stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

返回值------成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。
c 复制代码
//fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
参数------ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
      size -- 这是要读取的每个元素的大小,以字节为单位。
      nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
      stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
返回值------如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误

实例:

c 复制代码
//首先使用fwrite写入二进制数据,然后用fread读出
#include <stdio.h>

int main() {
    // 创建一个包含二进制数据的数组
    int data_to_write[5] = { 1, 2, 3, 4, 5 };

    // 打开一个二进制文件以供写入
    FILE* file_write = fopen("binary_data.bin", "wb");

    if (file_write == NULL) {
        perror("无法打开文件");
        return 1;
    }

    // 使用 fwrite 写入二进制数据到文件
    size_t elements_written = fwrite(data_to_write, sizeof(int), 5, file_write);

    if (elements_written < 5) {
        perror("写入文件时出错");
        fclose(file_write);
        return 1;
    }

    // 关闭文件
    fclose(file_write);

    // 打开同一个二进制文件以供读取
    FILE* file_read = fopen("binary_data.bin", "rb");

    if (file_read == NULL) {
        perror("无法打开文件");
        return 1;
    }

    // 从文件中读取二进制数据
    int data_read[5];

    size_t elements_read = fread(data_read, sizeof(int), 5, file_read);

    if (elements_read < 5) {
        perror("读取文件时出错");
        fclose(file_read);
        return 1;
    }

    // 关闭文件
    fclose(file_read);

    // 打印读取的数据
    printf("读取的数据:");
    for (size_t i = 0; i < elements_read; i++) {
        printf("%d ", data_read[i]);
    }
    printf("\n");

    return 0;
}

运行结果:

二进制文件:


1.2 比较一些函数

输入函数 功能 函数声明
scanf 从标准输入(通常是键盘)读取格式化输入 *int scanf(const char format, ...);
fscanf 从文件流中读取格式化输入 int fscanf(FILE *stream, const char *format, ...);
sscanf 从字符串中读取格式化输入 int sscanf(const char *str, const char *format, ...);
输入函数 功能 函数声明
printf 将格式化的输出写入到标准输出(通常是终端屏幕) int printf(const char *format, ...);
fprintf 将格式化的输出写入到文件流 int fprintf(FILE *stream, const char *format, ...);
sprintf 将格式化的输出写入到字符串 int sprintf(char *str, const char *format, ...);

可以看到,fscanf 和 sscanf 与 fprintf 和 sprintf ,跟scanf 和 sprintf 的使用是相似的,唯一不同的是,它们输入和输出函数从不同的源(标准输入、文件、字符串)读取数据,或将数据输出到不同的目标(标准输出、文件、字符串)。

实例:

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {
    int num;
    char name[20];
    FILE* file;

    // 输入函数示例
    printf("请输入一个整数:");
    scanf("%d", &num); // 从标准输入读取整数,并放入num

    file = fopen("input.txt", "r");
    if (file != NULL) {
    
        // 从文件中读取一个字符串,并放入name(提前创建input.txt,并将"Hello,"保存在文件中)
        fscanf(file, "%s", name); 
        fclose(file);
    }

    char input_string[] = "John";
    // 从字符串中解析整数和字符串,
    //已经在input.txt中读取了字符串"Hello,"并放在了name中
    //需要在name加上6个偏移量处读取input_string字符串,防止字符串被覆盖
    sscanf(input_string, "%s", name + 6);

    // 输出函数示例
    printf("整数:%d\n", num); // 输出到标准输出,预期结果  整数:20
    file = fopen("output.txt", "w");
    if (file != NULL) {
        fprintf(file, "整数:%d\n", num); // 输出到文件output.txt,预期结果  整数:20
        fclose(file);
    }

    char output_string[50];
    sprintf(output_string, "Hello,%s!", name); // 输出到字符串,预期结果  Hello,Hello,John!
    printf("%s\n", output_string);

    return 0;
}

创建文件:

运行结果:


在上一篇博客【C语言】文件操作(一)中我们讲到标准流的时候,我们说:实际上 stdin stdout stderr 都是在C标准库中定义的全局变量,具有与 FILE* 类型相同的类型。这使得它们可以作为参数传递给标准库函数。

为了证明这一点,举例:

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {
    int num;

    // 从标准输入(键盘)读取数据
    printf("请输入一个整数:");
    fscanf(stdin,"%d", &num);

    // 将错误消息写入标准错误
    if (num < 0) {
        fprintf(stderr, "错误:输入的数字不能为负数\n");
        return 1;
    }

    // 输出结果到标准输出
    fprintf(stdout,"您输入的数字是:%d\n", num);

    return 0;
}

但在实际应用中我们并不需要这样做,因为程序在启动的时候,标准流是默认打开的,scanf 和 printf就可以满足我们在从键盘输⼊数据,向屏幕上输出数据。



如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨11 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜13 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa13 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio