前言
C语言中的外部数据组织涉及文件的处理。文件是一种用于存储和读取数据的数据结构。在C语言中,我们可以使用文件来保存和管理大量的数据,包括文本文件和二进制文件。
十一、外部数据组织——文件
11.1 重新考虑户籍管理问题——文件
11.2 文件概述
文件是存储在外部介质上的一组相关数据。它可以是文本文件,包含可读的字符数据,也可以是二进制文件,包含不可读的二进制数据。
11.2.1 文件分类
主要有文本文件和二进制文件两种类型。文本文件是由字符组成的文件,可以使用文本编辑器打开查看和编辑。二进制文件是由二进制数据组成的文件,不可直接查看和编辑。
11.2.2 文件指针、标记及文件操作
文件指针是一个指向文件位置的指针,用于在文件中定位和操作数据。文件标记是用于标识文件中特定位置的标识符。文件操作包括打开文件、关闭文件、读取文件和写入文件等。
11.3 打开、关闭文件
在C语言中,可以使用fopen函数来打开文件,并使用fclose函数来关闭文件。打开文件时,需要指定文件名和打开模式,打开模式可以是读模式、写模式或追加模式等。
代码语言:javascript复制#include <stdio.h>
int main() {
FILE *file;
char *filename = "example.txt";
char *mode = "r"; // 使用 "r" 模式打开文件(只读模式)
// 打开文件
file = fopen(filename, mode);
if (file == NULL) {
printf("无法打开文件:%sn", filename);
return 1;
}
// 在这里可以进行读取文件内容的操作
// 关闭文件
fclose(file);
return 0;
}
11.4 I/O操作
11.4.1 字符读写
使用fgetc函数读取一个字符,使用fputc函数写入一个字符。
代码语言:javascript复制#include <stdio.h>
int main() {
FILE *file;
char ch;
// 打开文件
file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件n");
return 1;
}
// 逐个字符读取并输出文件内容
while ((ch = fgetc(file)) != EOF) {
printf("%c", ch);
}
// 关闭文件
fclose(file);
return 0;
}
11.4.2 字符串读写
使用fgets函数读取一行字符串,使用fputs函数写入一个字符串。
代码语言:javascript复制#include <stdio.h>
int main() {
FILE *file;
char str[100];
// 打开文件
file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件n");
return 1;
}
// 读取一行字符串并输出
fgets(str, sizeof(str), file);
printf("%s", str);
// 关闭文件
fclose(file);
return 0;
}
11.4.3 格式化读写
使用fscanf函数按照指定的格式从文件中读取数据,使用fprintf函数按照指定的格式将数据写入文件
代码语言:javascript复制#include <stdio.h>
int main() {
FILE *file;
int num1, num2;
float num3;
// 打开文件以供读写
file = fopen("data.txt", "w ");
if (file == NULL) {
printf("无法打开文件!n");
return 1;
}
// 向文件中写入数据
fprintf(file, "%d %d %.2f", 10, 20, 3.14);
// 将文件指针移动到文件开头
fseek(file, 0, SEEK_SET);
// 从文件中读取数据
fscanf(file, "%d %d %f", &num1, &num2, &num3);
// 输出读取的数据
printf("读取的数据:%d %d %.2fn", num1, num2, num3);
// 关闭文件
fclose(file);
return 0;
}
11.4.4 数据块读写
使用fread函数读取一块数据,使用fwrite函数写入一块数据。
代码语言:javascript复制#include <stdio.h>
typedef struct {
int id;
char name[20];
float salary;
} Employee;
int main() {
FILE *file;
Employee employees[3];
// 打开文件以供读写
file = fopen("employees.bin", "wb ");
if (file == NULL) {
printf("无法打开文件!n");
return 1;
}
// 写入数据块
employees[0].id = 1;
strcpy(employees[0].name, "John");
employees[0].salary = 5000.0;
employees[1].id = 2;
strcpy(employees[1].name, "Alice");
employees[1].salary = 6000.0;
employees[2].id = 3;
strcpy(employees[2].name, "Bob");
employees[2].salary = 5500.0;
fwrite(employees, sizeof(Employee), 3, file);
// 将文件指针移动到文件开头
fseek(file, 0, SEEK_SET);
// 读取数据块
fread(employees, sizeof(Employee), 3, file);
// 输出读取的数据
for (int i = 0; i < 3; i ) {
printf("员工%d:n", i 1);
printf("ID:%dn", employees[i].id);
printf("姓名:%sn", employees[i].name);
printf("工资:%.2fn", employees[i].salary);
printf("n");
}
// 关闭文件
fclose(file);
return 0;
}
11.4.5 文件定位
文件定位是指在文件中移动文件指针的操作。在C语言中,可以使用fseek()
函数进行文件定位。fseek()
函数的原型如下:
int fseek(FILE *stream, long offset, int whence);
其中,stream
是一个指向FILE结构的指针,表示要进行定位的文件;offset
表示要移动的字节数或记录数;whence
表示起始位置,可以是以下常量之一:
SEEK_SET
:从文件开头开始计算偏移量。SEEK_CUR
:从当前位置开始计算偏移量。SEEK_END
:从文件末尾开始计算偏移量。
#include <stdio.h>
int main() {
FILE *file;
char ch;
// 打开文件供读取
file = fopen("data.txt", "r");
if (file == NULL) {
printf("无法打开文件!n");
return 1;
}
// 将文件指针移动到文件末尾
fseek(file, 0, SEEK_END);
// 获取文件大小(字节数)
long size = ftell(file);
// 从文件末尾向前读取数据
for (long i = size - 1; i >= 0; i--) {
fseek(file, i, SEEK_SET);
ch = fgetc(file);
printf("%c", ch);
}
// 关闭文件
fclose(file);
return 0;
}
首先使用fopen()
函数打开一个名为"data.txt"的文件,使用"r"模式表示只读取文件内容。然后使用fseek()
函数将文件指针移动到文件末尾,使用ftell()
函数获取文件大小(字节数)。接下来,使用循环从文件末尾向前读取数据,每次将文件指针移动到指定位置并使用fgetc()
函数读取一个字符,并将其输出到控制台。最后使用fclose()
函数关闭文件。
11.5 与操作系统文件联系——程序参数
11.5.1 程序参数
程序参数是指在执行程序时通过命令行传递给程序的额外信息。通过使用程序参数,可以在程序运行时向程序传递不同的数据或配置选项,从而实现更灵活的程序行为。与操作系统文件的联系在于,程序参数可以包含文件路径或文件名等信息,以便程序能够读取或操作指定的文件。例如,用户可以通过命令行输入文件路径作为程序参数,然后程序可以使用该路径打开文件并进行相应的操作。
在C语言中,程序参数可以通过main()
函数的参数获取。main()
函数的标准形式为:
int main(int argc, char *argv[])
其中,argc
表示命令行参数的数量,argv
是一个指向指针的指针,用于存储命令行参数的字符串数组。argv[0]
存储程序的名称,argv[1]
、argv[2]
等依次存储传递给程序的参数字符串。
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("请指定文件路径作为参数!n");
return 1;
}
FILE *file;
char ch;
// 打开指定的文件供读取
file = fopen(argv[1], "r");
if (file == NULL) {
printf("无法打开文件:%sn", argv[1]);
return 1;
}
// 读取文件内容并输出到控制台
while ((ch = fgetc(file)) != EOF) {
printf("%c", ch);
}
// 关闭文件
fclose(file);
return 0;
}
11.5.2 健壮性与exit函数
健壮性是指程序的强壮性和容错能力,即在面对异常或错误情况时,程序能够正常运行或适当地处理错误,而不会崩溃或产生无法预料的结果。
在C语言中,可以使用exit()
函数来终止程序的执行并返回到操作系统。exit()
函数的原型:
void exit(int status);
其中,status
表示程序的退出状态码,通常用于向操作系统传递程序的执行结果或状态信息。一般约定,状态码为0表示程序执行成功,非零值表示程序执行失败或出现错误。
在编写健壮的程序时,可以根据具体情况使用exit()
函数来处理错误或异常。例如,当程序无法打开所需的文件时,可以使用exit()
函数终止程序的执行,并返回一个非零的状态码,以便通知操作系统程序执行失败。
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file;
// 打开文件供读取
file = fopen("data.txt", "r");
if (file == NULL) {
printf("无法打开文件!n");
exit(1); // 终止程序执行并返回状态码1
}
// 读取文件内容并输出到控制台
char ch;
while ((ch = fgetc(file)) != EOF) {
printf("%c", ch);
}
// 关闭文件
fclose(file);
return 0;
}
我们尝试打开一个名为"data.txt"的文件供读取。如果文件打开失败(即file
为NULL
),则输出错误消息并使用exit(1)
终止程序的执行,并返回状态码1。这个状态码可以表示执行失败的情况。
通过使用exit()
函数,可以在程序遇到无法继续执行的错误或异常情况时,及时终止程序的执行,避免产生不确定的结果或进一步的错误。
11.5.3 给定程序参数
可以通过命令行参数或其他方式将参数传递给程序,然后程序可以根据参数进行相应的操作。
待完善