最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

[c语言日寄]文件操作

网站源码admin0浏览0评论

[c语言日寄]文件操作

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是进阶开发者,这里都能满足你的需求! 【食用方法】1.根据题目自行尝试 2.查看基础思路完善题解 3.学习拓展算法 【Gitee链接】资源保存在我的Gitee仓库:

前言

在C语言的世界中,文件操作是一个不可或缺的技能。无论是数据的存储、读取还是处理,文件操作都扮演着关键的角色。从简单的文本文件到复杂的二进制文件,C语言提供了丰富的函数和工具来帮助我们高效地完成这些任务。今天,我们将深入探讨C语言中的文件操作,从基础的文件打开和关闭,到复杂的顺序读写和随机读写,再到文本文件和二进制文件的区别,以及文件缓冲区的使用。

知识点分析

文件的分类

在C语言中,文件主要分为两类:程序文件和数据文件。程序文件包括源程序文件(.c)、目标文件(.obj)和可执行程序(.exe)。这些文件主要用于程序的编译和运行。而本章我们主要讨论的是数据文件,即用于存储数据的文件。

文件名

文件名通常包含三部分:文件路径、文件名主干和文件后缀。文件路径可以是绝对路径或相对路径。绝对路径是从根目录开始的完整路径,而相对路径则是相对于当前工作目录的路径。例如,当文件位于工程文件夹中时,可以使用相对路径test.txt;如果文件位于上一级目录中,则可以使用../test.txt

文件的打开和关闭

在C语言中,文件操作的核心是文件指针。每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,如文件名、文件状态和当前文件的位置。这些信息被保存在一个结构体变量中,这个结构体变量由系统声明,取名为FILE。文件位置指针是文件指针的成员之一,用于确定文件光标位置。

文件的打开

文件在读写之前需要先打开。C语言提供了fopen函数来打开文件。fopen函数的原型如下:

代码语言:javascript代码运行次数:0运行复制
FILE *fopen(const char *filename, const char *mode);
  • 参数
    • filename:文件路径,可以是相对路径或绝对路径。
    • mode:文件使用方式,常见的模式有:
      • "r":只读模式,文件必须存在。
      • "w":只写模式,如果文件存在则清空内容,如果文件不存在则创建。
      • "a":追加模式,如果文件存在则在文件末尾追加内容,如果文件不存在则创建。
      • "r+":读写模式,文件必须存在。
      • "w+":读写模式,如果文件存在则清空内容,如果文件不存在则创建。
      • "a+":读写模式,如果文件存在则在文件末尾追加内容,如果文件不存在则创建。
  • 返回值
    • 成功返回文件指针,失败返回NULL
文件的关闭

使用完文件后,应该关闭文件以释放资源。C语言提供了fclose函数来关闭文件。fclose函数的原型如下:

代码语言:javascript代码运行次数:0运行复制
int fclose(FILE *stream);
  • 参数
    • stream:文件指针。
  • 返回值
    • 成功返回0,失败返回EOF

需要注意的是,关闭文件后,文件指针会变成野指针,因此需要将存储文件指针的变量置为NULL,以避免潜在的错误。

文件的顺序读写

文件的顺序读写是指按照文件的顺序逐个读取或写入数据。C语言提供了多种函数来实现顺序读写,其中最常用的是fgetsfputs

fgets函数

fgets函数用于从文件中读取一行数据,并将其存储到指定的字符串中。其原型如下:

代码语言:javascript代码运行次数:0运行复制
char *fgets(char *str, int num, FILE *stream);
  • 参数
    • str:存储读取数据的字符串。
    • num:最大读取字符数(包括末尾的'\0')。
    • stream:文件指针。
  • 返回值
    • 成功返回str,失败返回NULL

fgets函数会从文件中读取最多num-1个字符,直到遇到换行符或文件结束符。读取完成后,会在字符串末尾自动添加'\0'

fputs函数

fputs函数用于将字符串写入文件。其原型如下:

代码语言:javascript代码运行次数:0运行复制
int fputs(const char *str, FILE *stream);
  • 参数
    • str:要写入的字符串。
    • stream:文件指针。
  • 返回值
    • 成功返回非负值,失败返回EOF
补充函数

除了fgetsfputs,C语言还提供了sprintfsscanf函数,用于格式化字符串和从字符串中读取数据。

  • sprintf函数
代码语言:javascript代码运行次数:0运行复制
int sprintf(char *str, const char *format, ...);

sprintf函数将格式化的字符串写入到str中。它类似于printf,但输出目标是字符串而不是标准输出。

  • sscanf函数
代码语言:javascript代码运行次数:0运行复制
int sscanf(const char *s, const char *format, ...);

sscanf函数从字符串s中读取数据,并根据格式化字符串format将数据存储到指定的变量中。它类似于scanf,但输入源是字符串而不是标准输入。

文件的随机读写

文件的随机读写是指可以任意定位文件中的某个位置进行读写操作。这在处理大型文件或需要频繁访问特定数据时非常有用。C语言提供了fseekftellrewind函数来实现随机读写。

文件位置指针

文件位置指针是FILE结构体的一部分,指向文件中当前读写的位置(光标位置)。打开文件时,默认指向文件的起始位置。

fseek函数

fseek函数用于定位文件位置指针。其原型如下:

代码语言:javascript代码运行次数:0运行复制
int fseek(FILE *stream, long int offset, int origin);
  • 参数
    • stream:文件指针。
    • offset:偏移量,表示从origin位置开始移动的字节数。
    • origin:起始位置,常见的值有:
      • SEEK_SET:文件开头。
      • SEEK_CUR:当前位置。
      • SEEK_END:文件结尾。
  • 返回值
    • 成功返回0,失败返回非零值。
ftell函数

ftell函数用于获取当前文件位置指针的位置。其原型如下:

代码语言:javascript代码运行次数:0运行复制
long int ftell(FILE *stream);
  • 参数
    • stream:文件指针。
  • 返回值
    • 返回当前文件位置指针的位置(长整型值)。
rewind函数

rewind函数用于将文件位置指针重新定位到文件的起始位置。其原型如下:

代码语言:javascript代码运行次数:0运行复制
void rewind(FILE *stream);
  • 参数
    • stream:文件指针。
文本文件和二进制文件

根据数据的组织形式,数据文件可以分为文本文件和二进制文件。

文本文件

文本文件以ASCII码字符形式存储数据。在内存中,数据以二进制形式存储,但在存储到文件时会转换为ASCII码。文本文件的内容可以通过文本编辑器直接查看和编辑。

二进制文件

二进制文件以二进制形式存储数据。数据在内存中以二进制形式存储,并且直接输出到文件中,不进行任何转换。二进制文件的内容受大小端影响,因此不方便直接用文本编辑器查看和编辑。

文件读取结束的判定

在读取文件时,需要判断是否到达文件末尾。

  • feof函数
代码语言:javascript代码运行次数:0运行复制
int feof(FILE *stream);

feof函数用于判断文件是否已经到达末尾。如果文件正常读写并遇到文件尾,则返回非零值;否则返回0

  • ferror函数
代码语言:javascript代码运行次数:0运行复制
int ferror(FILE *stream);

ferror函数用于判断文件在读取过程中是否出错。如果文件读取过程中出现错误,则返回非零值;否则返回0

需要注意的是,不能使用feof的返回值直接判断文件是否结束。正确的做法是结合fgetcfgetsfread的返回值来判断。

  • 文本文件
    • 判断fgetc的返回值是否为EOF
    • 判断fgets的返回值是否为NULL
  • 二进制文件
    • 判断fread的返回值是否小于实际要读的个数。
文件缓冲区

ANSI C标准规定,系统会自动为每个正在使用的文件开辟一段文件缓冲区。当从内存向磁盘输出数据时,数据会先写入缓冲区,当缓冲区满了之后,再一起写入磁盘。关闭文件时,缓冲区也会被刷新(fclose)。从磁盘向内存输入数据时,数据会先读入缓冲区,当缓冲区满了之后,再逐个将数据送到程序数据区。

fflush函数

fflush函数用于刷新缓冲区。其原型如下:

代码语言:javascript代码运行次数:0运行复制
int fflush(FILE *stream);
  • 参数
    • stream:文件指针。
  • 返回值
    • 成功返回0,失败返回非零值。

需要注意的是,在高版本的Visual Studio中,fflush函数可能无法使用。

setbuf函数

setbuf函数用于设置缓冲区的大小。其原型如下:

代码语言:javascript代码运行次数:0运行复制
void setbuf(FILE *stream, char *buf);
  • 参数
    • stream:文件指针。
    • buf:缓冲区指针。如果bufNULL,则关闭缓冲区。

注意事项

  1. 文件指针的管理
    • 打开文件后,文件指针指向文件的起始位置。
    • 关闭文件后,文件指针会变成野指针,需要将其置为NULL,以避免潜在的错误。
  2. 文件打开失败的处理
    • 使用fopen打开文件时,如果返回NULL,表示文件打开失败。此时,应检查文件路径和文件模式是否正确,以及文件是否存在。
  3. 文件读取结束的判断
    • 不能直接使用feof的返回值来判断文件是否结束。对于文本文件,应结合fgetcfgets的返回值;对于二进制文件,应结合fread的返回值。
  4. 文件缓冲区的刷新
    • 在高版本的Visual Studio中,fflush函数可能无法使用。如果需要刷新缓冲区,可以考虑使用fclose和重新打开文件的方式。
  5. 文件路径的处理
    • 文件路径可以是绝对路径或相对路径。相对路径是从当前工作目录开始的路径,因此在使用相对路径时,需要确保当前工作目录正确。
  6. 文件读写的安全性
    • 在读写文件时,应确保文件的权限正确,避免因权限不足导致的错误。

拓展应用

文件内容的统计
统计文本文件的行数、单词数和字符数

我们可以编写一个程序来统计文本文件的行数、单词数和字符数。以下是一个简单的示例代码:

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <ctype.h>

int main() {
    FILE *file = fopen("test.txt", "r");
    if (file == NULL) {
        perror("Error opening file");
        return -1;
    }

    int lines = 0, words = 0, chars = 0;
    int in_word = 0;
    char c;

    while ((c = fgetc(file)) != EOF) {
        chars++;
        if (c == '\n') {
            lines++;
        }
        if (isspace(c)) {
            in_word = 0;
        } else {
            if (!in_word) {
                words++;
                in_word = 1;
            }
        }
    }

    if (chars > 0 && c != '\n') {
        lines++;
    }

    fclose(file);

    printf("Lines: %d\n", lines);
    printf("Words: %d\n", words);
    printf("Characters: %d\n", chars);

    return 0;
}
文件内容的复制
复制文本文件的内容

我们可以编写一个程序来复制文本文件的内容到另一个文件。以下是一个简单的示例代码:

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>

int main() {
    FILE *source = fopen("source.txt", "r");
    if (source == NULL) {
        perror("Error opening source file");
        return -1;
    }

    FILE *destination = fopen("destination.txt", "w");
    if (destination == NULL) {
        perror("Error opening destination file");
        fclose(source);
        return -1;
    }

    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), source) != NULL) {
        fputs(buffer, destination);
    }

    fclose(source);
    fclose(destination);

    printf("File copied successfully.\n");

    return 0;
}
二进制文件的读写
读写结构体数据到二进制文件

我们可以编写一个程序来将结构体数据写入二进制文件,并从二进制文件中读取结构体数据。以下是一个简单的示例代码:

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>

struct student {
    int id;
    char name[50];
    float score;
};

void write_student_to_file(const char *filename, struct student *s) {
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }

    if (fwrite(s, sizeof(struct student), 1, file) != 1) {
        perror("Error writing to file");
    }

    fclose(file);
}

void read_student_from_file(const char *filename, struct student *s) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }

    if (fread(s, sizeof(struct student), 1, file) != 1) {
        perror("Error reading from file");
    }

    fclose(file);
}

int main() {
    struct student s = {1, "Alice", 95.5};
    write_student_to_file("student.bin", &s);

    struct student s2;
    read_student_from_file("student.bin", &s2);

    printf("ID: %d, Name: %s, Score: %.2f\n", s2.id, s2.name, s2.score);

    return 0;
}
文件的备份和恢复
备份和恢复文件

我们可以编写一个程序来备份文件,并在需要时恢复文件。以下是一个简单的示例代码:

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>
#include <string.h>

void backup_file(const char *source, const char *backup) {
    FILE *src = fopen(source, "rb");
    if (src == NULL) {
        perror("Error opening source file");
        return;
    }

    FILE *bkp = fopen(backup, "wb");
    if (bkp == NULL) {
        perror("Error opening backup file");
        fclose(src);
        return;
    }

    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), src) != NULL) {
        fputs(buffer, bkp);
    }

    fclose(src);
    fclose(bkp);
}

void restore_file(const char *backup, const char *destination) {
    FILE *bkp = fopen(backup, "rb");
    if (bkp == NULL) {
        perror("Error opening backup file");
        return;
    }

    FILE *dst = fopen(destination, "wb");
    if (dst == NULL) {
        perror("Error opening destination file");
        fclose(bkp);
        return;
    }

    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), bkp) != NULL) {
        fputs(buffer, dst);
    }

    fclose(bkp);
    fclose(dst);
}

int main() {
    backup_file("original.txt", "backup.txt");
    restore_file("backup.txt", "restored.txt");

    printf("File backed up and restored successfully.\n");

    return 0;
}

总结

通过以上示例,我们可以看到C语言中的文件操作功能强大且灵活。无论是简单的文件读写,还是复杂的文件处理,C语言都能提供相应的支持。

关注窝,每三天至少更新一篇优质c语言题目详解~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-03-31,如有侵权请联系 cloudcommunity@tencent 删除指针字符串二进制函数数据

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论