Appearance
文件读写
在C语言中,文件操作是程序与外部数据交互的重要方式。C语言提供了一组丰富的文件I/O函数,用于打开、读取、写入和关闭文件。
文件指针
在C语言中,文件通过文件指针来操作。文件指针是一个指向FILE结构体的指针,该结构体包含了文件的所有信息,如文件名、文件位置指示器、文件状态等。
c
FILE *fp;打开文件
使用fopen()函数打开文件:
c
FILE *fopen(const char *filename, const char *mode);文件打开模式
| 模式 | 描述 | 文件不存在时 |
|---|---|---|
"r" | 只读,文件必须存在 | 返回NULL |
"w" | 只写,覆盖原有内容 | 创建新文件 |
"a" | 追加,在文件末尾写入 | 创建新文件 |
"r+" | 读写,文件必须存在 | 返回NULL |
"w+" | 读写,覆盖原有内容 | 创建新文件 |
"a+" | 读写,在文件末尾写入 | 创建新文件 |
"rb" | 二进制只读 | 返回NULL |
"wb" | 二进制只写 | 创建新文件 |
"ab" | 二进制追加 | 创建新文件 |
c
#include <stdio.h>
int main() {
FILE *fp;
// 以只读模式打开文件
fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
// 文件操作...
fclose(fp);
return 0;
}关闭文件
使用fclose()函数关闭文件:
c
int fclose(FILE *stream);关闭文件时,所有缓冲的数据都会被写入文件。成功关闭返回0,失败返回EOF。
c
if (fclose(fp) != 0) {
printf("关闭文件时出错\n");
}字符级文件操作
写入字符
c
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);c
#include <stdio.h>
int main() {
FILE *fp = fopen("output.txt", "w");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
// 写入单个字符
fputc('H', fp);
fputc('e', fp);
fputc('l', fp);
fputc('l', fp);
fputc('o', fp);
fclose(fp);
return 0;
}读取字符
c
int fgetc(FILE *stream);
int getc(FILE *stream);c
#include <stdio.h>
int main() {
FILE *fp = fopen("input.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
fclose(fp);
return 0;
}字符串级文件操作
写入字符串
c
int fputs(const char *s, FILE *stream);c
#include <stdio.h>
int main() {
FILE *fp = fopen("output.txt", "w");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
fputs("Hello, World!\n", fp);
fputs("This is a test.\n", fp);
fclose(fp);
return 0;
}读取字符串
c
char *fgets(char *s, int size, FILE *stream);fgets()读取一行字符串,包括换行符,最多读取size-1个字符。
c
#include <stdio.h>
int main() {
FILE *fp = fopen("input.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
char buffer[256];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
return 0;
}格式化文件操作
格式化写入
c
int fprintf(FILE *stream, const char *format, ...);c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "w");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
int age = 25;
float score = 95.5;
char name[] = "张三";
fprintf(fp, "姓名: %s\n", name);
fprintf(fp, "年龄: %d\n", age);
fprintf(fp, "分数: %.2f\n", score);
fclose(fp);
return 0;
}格式化读取
c
int fscanf(FILE *stream, const char *format, ...);c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
char name[50];
int age;
float score;
fscanf(fp, "姓名: %s\n", name);
fscanf(fp, "年龄: %d\n", &age);
fscanf(fp, "分数: %f\n", &score);
printf("姓名: %s\n", name);
printf("年龄: %d\n", age);
printf("分数: %.2f\n", score);
fclose(fp);
return 0;
}二进制文件操作
写入二进制数据
c
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);c
#include <stdio.h>
typedef struct {
char name[50];
int age;
float score;
} Student;
int main() {
FILE *fp = fopen("students.dat", "wb");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
Student students[] = {
{"张三", 20, 85.5},
{"李四", 21, 92.0},
{"王五", 19, 78.5}
};
int count = sizeof(students) / sizeof(students[0]);
fwrite(students, sizeof(Student), count, fp);
fclose(fp);
return 0;
}读取二进制数据
c
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);c
#include <stdio.h>
typedef struct {
char name[50];
int age;
float score;
} Student;
int main() {
FILE *fp = fopen("students.dat", "rb");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
Student students[3];
fread(students, sizeof(Student), 3, fp);
for (int i = 0; i < 3; i++) {
printf("姓名: %s, 年龄: %d, 分数: %.2f\n",
students[i].name, students[i].age, students[i].score);
}
fclose(fp);
return 0;
}文件定位
获取当前位置
c
long ftell(FILE *stream);返回当前文件位置指示器的值。
c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
long pos = ftell(fp);
printf("当前位置: %ld\n", pos);
fclose(fp);
return 0;
}设置文件位置
c
int fseek(FILE *stream, long offset, int whence);whence参数:
SEEK_SET: 从文件开头开始SEEK_CUR: 从当前位置开始SEEK_END: 从文件末尾开始
c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
// 移动到文件开头
fseek(fp, 0, SEEK_SET);
// 移动到文件末尾
fseek(fp, 0, SEEK_END);
// 从当前位置向前移动10个字节
fseek(fp, -10, SEEK_CUR);
fclose(fp);
return 0;
}重置文件位置
c
void rewind(FILE *stream);将文件位置指示器重置到文件开头。
c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
// 读取文件
char ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
// 重置到文件开头
rewind(fp);
// 再次读取文件
printf("\n--- 第二次读取 ---\n");
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
fclose(fp);
return 0;
}文件结束检测
c
int feof(FILE *stream);检测是否到达文件末尾。
c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
char ch;
while (!feof(fp)) {
ch = fgetc(fp);
if (ch != EOF) {
putchar(ch);
}
}
fclose(fp);
return 0;
}文件错误检测
c
int ferror(FILE *stream);检测文件操作是否出错。
c
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
char ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
if (ferror(fp)) {
printf("\n文件读取出错\n");
}
fclose(fp);
return 0;
}标准文件流
C语言提供了三个标准文件流:
| 文件流 | 描述 | 默认设备 |
|---|---|---|
stdin | 标准输入 | 键盘 |
stdout | 标准输出 | 屏幕 |
stderr | 标准错误 | 屏幕 |
c
#include <stdio.h>
int main() {
// 从标准输入读取
printf("请输入一个整数: ");
int num;
scanf("%d", &num);
// 输出到标准输出
fprintf(stdout, "你输入的数字是: %d\n", num);
// 输出到标准错误
fprintf(stderr, "这是一个错误信息\n");
return 0;
}完整示例:学生成绩管理系统
c
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[50];
float score;
} Student;
void addStudent() {
FILE *fp = fopen("students.dat", "ab");
if (fp == NULL) {
printf("无法打开文件\n");
return;
}
Student s;
printf("学号: ");
scanf("%d", &s.id);
printf("姓名: ");
scanf("%s", s.name);
printf("分数: ");
scanf("%f", &s.score);
fwrite(&s, sizeof(Student), 1, fp);
fclose(fp);
printf("学生信息已添加\n");
}
void displayStudents() {
FILE *fp = fopen("students.dat", "rb");
if (fp == NULL) {
printf("没有学生记录\n");
return;
}
Student s;
printf("\n学号\t姓名\t分数\n");
printf("------------------------\n");
while (fread(&s, sizeof(Student), 1, fp) == 1) {
printf("%d\t%s\t%.2f\n", s.id, s.name, s.score);
}
fclose(fp);
}
void searchStudent() {
int id;
printf("请输入要查找的学号: ");
scanf("%d", &id);
FILE *fp = fopen("students.dat", "rb");
if (fp == NULL) {
printf("没有学生记录\n");
return;
}
Student s;
int found = 0;
while (fread(&s, sizeof(Student), 1, fp) == 1) {
if (s.id == id) {
printf("\n学号: %d\n", s.id);
printf("姓名: %s\n", s.name);
printf("分数: %.2f\n", s.score);
found = 1;
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生\n", id);
}
fclose(fp);
}
int main() {
int choice;
while (1) {
printf("\n学生成绩管理系统\n");
printf("1. 添加学生\n");
printf("2. 显示所有学生\n");
printf("3. 查找学生\n");
printf("4. 退出\n");
printf("请选择: ");
scanf("%d", &choice);
switch (choice) {
case 1:
addStudent();
break;
case 2:
displayStudents();
break;
case 3:
searchStudent();
break;
case 4:
exit(0);
default:
printf("无效选择\n");
}
}
return 0;
}文件操作注意事项
检查文件是否成功打开
cFILE *fp = fopen("file.txt", "r"); if (fp == NULL) { printf("无法打开文件\n"); return 1; }及时关闭文件
cfclose(fp);检查文件操作是否成功
cif (fwrite(&data, sizeof(data), 1, fp) != 1) { printf("写入失败\n"); }处理二进制文件和文本文件的区别
- 文本文件:以字符形式存储,适合存储文本数据
- 二进制文件:以二进制形式存储,适合存储结构化数据
注意文件定位操作
- 在读取和写入之间切换时,需要使用
fseek()或fflush() - 在追加模式下,所有写入操作都在文件末尾进行
- 在读取和写入之间切换时,需要使用
错误处理
cif (ferror(fp)) { perror("文件操作出错"); clearerr(fp); }
总结
C语言的文件I/O操作提供了强大而灵活的功能,包括:
- 文本文件和二进制文件的读写
- 字符、字符串、格式化和块级数据操作
- 文件定位和随机访问
- 错误检测和处理
掌握文件操作对于编写实用的C程序非常重要,它使程序能够持久化数据、处理大量数据,并与外部世界进行数据交换。