【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就可以满足我们在从键盘输⼊数据,向屏幕上输出数据。



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

相关推荐
&岁月不待人&21 分钟前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
StayInLove25 分钟前
G1垃圾回收器日志详解
java·开发语言
TeYiToKu26 分钟前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
无尽的大道33 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
互联网打工人no133 分钟前
每日一题——第一百二十四题
c语言
爱吃生蚝的于勒36 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~40 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
binishuaio1 小时前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE1 小时前
【Java SE】StringBuffer
java·开发语言
就是有点傻1 小时前
WPF中的依赖属性
开发语言·wpf