[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
函数的原型如下:
FILE *fopen(const char *filename, const char *mode);
- 参数:
filename
:文件路径,可以是相对路径或绝对路径。mode
:文件使用方式,常见的模式有:"r"
:只读模式,文件必须存在。"w"
:只写模式,如果文件存在则清空内容,如果文件不存在则创建。"a"
:追加模式,如果文件存在则在文件末尾追加内容,如果文件不存在则创建。"r+"
:读写模式,文件必须存在。"w+"
:读写模式,如果文件存在则清空内容,如果文件不存在则创建。"a+"
:读写模式,如果文件存在则在文件末尾追加内容,如果文件不存在则创建。
- 返回值:
- 成功返回文件指针,失败返回
NULL
。
- 成功返回文件指针,失败返回
文件的关闭
使用完文件后,应该关闭文件以释放资源。C语言提供了fclose
函数来关闭文件。fclose
函数的原型如下:
int fclose(FILE *stream);
- 参数:
stream
:文件指针。
- 返回值:
- 成功返回
0
,失败返回EOF
。
- 成功返回
需要注意的是,关闭文件后,文件指针会变成野指针,因此需要将存储文件指针的变量置为NULL
,以避免潜在的错误。
文件的顺序读写
文件的顺序读写是指按照文件的顺序逐个读取或写入数据。C语言提供了多种函数来实现顺序读写,其中最常用的是fgets
和fputs
。
fgets函数
fgets
函数用于从文件中读取一行数据,并将其存储到指定的字符串中。其原型如下:
char *fgets(char *str, int num, FILE *stream);
- 参数:
str
:存储读取数据的字符串。num
:最大读取字符数(包括末尾的'\0'
)。stream
:文件指针。
- 返回值:
- 成功返回
str
,失败返回NULL
。
- 成功返回
fgets
函数会从文件中读取最多num-1
个字符,直到遇到换行符或文件结束符。读取完成后,会在字符串末尾自动添加'\0'
。
fputs函数
fputs
函数用于将字符串写入文件。其原型如下:
int fputs(const char *str, FILE *stream);
- 参数:
str
:要写入的字符串。stream
:文件指针。
- 返回值:
- 成功返回非负值,失败返回
EOF
。
- 成功返回非负值,失败返回
补充函数
除了fgets
和fputs
,C语言还提供了sprintf
和sscanf
函数,用于格式化字符串和从字符串中读取数据。
- sprintf函数:
int sprintf(char *str, const char *format, ...);
sprintf
函数将格式化的字符串写入到str
中。它类似于printf
,但输出目标是字符串而不是标准输出。
- sscanf函数:
int sscanf(const char *s, const char *format, ...);
sscanf
函数从字符串s
中读取数据,并根据格式化字符串format
将数据存储到指定的变量中。它类似于scanf
,但输入源是字符串而不是标准输入。
文件的随机读写
文件的随机读写是指可以任意定位文件中的某个位置进行读写操作。这在处理大型文件或需要频繁访问特定数据时非常有用。C语言提供了fseek
、ftell
和rewind
函数来实现随机读写。
文件位置指针
文件位置指针是FILE
结构体的一部分,指向文件中当前读写的位置(光标位置)。打开文件时,默认指向文件的起始位置。
fseek函数
fseek
函数用于定位文件位置指针。其原型如下:
int fseek(FILE *stream, long int offset, int origin);
- 参数:
stream
:文件指针。offset
:偏移量,表示从origin
位置开始移动的字节数。origin
:起始位置,常见的值有:SEEK_SET
:文件开头。SEEK_CUR
:当前位置。SEEK_END
:文件结尾。
- 返回值:
- 成功返回
0
,失败返回非零值。
- 成功返回
ftell函数
ftell
函数用于获取当前文件位置指针的位置。其原型如下:
long int ftell(FILE *stream);
- 参数:
stream
:文件指针。
- 返回值:
- 返回当前文件位置指针的位置(长整型值)。
rewind函数
rewind
函数用于将文件位置指针重新定位到文件的起始位置。其原型如下:
void rewind(FILE *stream);
- 参数:
stream
:文件指针。
文本文件和二进制文件
根据数据的组织形式,数据文件可以分为文本文件和二进制文件。
文本文件
文本文件以ASCII码字符形式存储数据。在内存中,数据以二进制形式存储,但在存储到文件时会转换为ASCII码。文本文件的内容可以通过文本编辑器直接查看和编辑。
二进制文件
二进制文件以二进制形式存储数据。数据在内存中以二进制形式存储,并且直接输出到文件中,不进行任何转换。二进制文件的内容受大小端影响,因此不方便直接用文本编辑器查看和编辑。
文件读取结束的判定
在读取文件时,需要判断是否到达文件末尾。
- feof函数:
int feof(FILE *stream);
feof
函数用于判断文件是否已经到达末尾。如果文件正常读写并遇到文件尾,则返回非零值;否则返回0
。
- ferror函数:
int ferror(FILE *stream);
ferror
函数用于判断文件在读取过程中是否出错。如果文件读取过程中出现错误,则返回非零值;否则返回0
。
需要注意的是,不能使用feof
的返回值直接判断文件是否结束。正确的做法是结合fgetc
、fgets
或fread
的返回值来判断。
- 文本文件:
- 判断
fgetc
的返回值是否为EOF
。 - 判断
fgets
的返回值是否为NULL
。
- 判断
- 二进制文件:
- 判断
fread
的返回值是否小于实际要读的个数。
- 判断
文件缓冲区
ANSI C标准规定,系统会自动为每个正在使用的文件开辟一段文件缓冲区。当从内存向磁盘输出数据时,数据会先写入缓冲区,当缓冲区满了之后,再一起写入磁盘。关闭文件时,缓冲区也会被刷新(fclose
)。从磁盘向内存输入数据时,数据会先读入缓冲区,当缓冲区满了之后,再逐个将数据送到程序数据区。
fflush函数
fflush
函数用于刷新缓冲区。其原型如下:
int fflush(FILE *stream);
- 参数:
stream
:文件指针。
- 返回值:
- 成功返回
0
,失败返回非零值。
- 成功返回
需要注意的是,在高版本的Visual Studio中,fflush
函数可能无法使用。
setbuf函数
setbuf
函数用于设置缓冲区的大小。其原型如下:
void setbuf(FILE *stream, char *buf);
- 参数:
stream
:文件指针。buf
:缓冲区指针。如果buf
为NULL
,则关闭缓冲区。
注意事项
- 文件指针的管理:
- 打开文件后,文件指针指向文件的起始位置。
- 关闭文件后,文件指针会变成野指针,需要将其置为
NULL
,以避免潜在的错误。
- 文件打开失败的处理:
- 使用
fopen
打开文件时,如果返回NULL
,表示文件打开失败。此时,应检查文件路径和文件模式是否正确,以及文件是否存在。
- 使用
- 文件读取结束的判断:
- 不能直接使用
feof
的返回值来判断文件是否结束。对于文本文件,应结合fgetc
或fgets
的返回值;对于二进制文件,应结合fread
的返回值。
- 不能直接使用
- 文件缓冲区的刷新:
- 在高版本的Visual Studio中,
fflush
函数可能无法使用。如果需要刷新缓冲区,可以考虑使用fclose
和重新打开文件的方式。
- 在高版本的Visual Studio中,
- 文件路径的处理:
- 文件路径可以是绝对路径或相对路径。相对路径是从当前工作目录开始的路径,因此在使用相对路径时,需要确保当前工作目录正确。
- 文件读写的安全性:
- 在读写文件时,应确保文件的权限正确,避免因权限不足导致的错误。
拓展应用
文件内容的统计
统计文本文件的行数、单词数和字符数
我们可以编写一个程序来统计文本文件的行数、单词数和字符数。以下是一个简单的示例代码:
代码语言: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 删除指针字符串二进制函数数据发布者:admin,转转请注明出处:http://www.yc00.com/web/1748049813a4724027.html
评论列表(0条)