2024-2025-1 20241314 《计算机基础与程序设计》第十二周学习总结
2024-2025-1 20241314 《计算机基础与程序设计》第十二周学习总结
作业信息
这个作业属于哪个课程 | 2024-2025-1-计算机基础与程序设计 |
---|---|
这个作业要求在哪里 | 2024-2025-1计算机基础与程序设计第十二周作业 |
这个作业的目标 | 复习 |
作业正文 | 正文 |
教材学习内容总结
-
引言与文件概述
- 在《C语言程序设计》的前几章,重点通常放在基本数据类型、控制结构和函数等内容上。到了第11章的文件部分,主要关注的是程序与外部存储设备(如硬盘)之间的数据交换。
- 文件是存储在外部介质上的数据集合,这些数据可以是程序代码、文本、图像、音频等各种形式。对于C程序而言,能够有效地操作文件是非常重要的,因为它允许程序保存和读取数据,从而实现数据的持久化存储。
-
文件类型与存储方式
- 文本文件
- 文本文件是基于字符编码(如ASCII或UTF - 8)存储的文件。在文本文件中,每个字符都有对应的编码值。例如,字符'A'在ASCII码中对应的十进制值是65。
- 当使用文本编辑器打开文本文件时,会将这些编码值转换为可识别的字符显示出来。文本文件的内容可以被人类直接阅读和理解。例如,一个简单的包含“Hello, World!”的文本文件,存储的就是这些字符对应的编码。
- 二进制文件
- 二进制文件以二进制形式存储数据,不是以字符编码的方式。它可以存储各种类型的数据,如整数、浮点数、结构体等。
- 例如,一个整数10在内存中以二进制形式存储(假设为32位整数,其二进制表示为00000000000000000000000000001010),在二进制文件中也是以类似的二进制形式存储。与文本文件不同,二进制文件内容如果直接打开查看,可能是一堆乱码,因为它不是按照字符编码来存储的。
- 文本文件
-
文件指针与
FILE
结构体- C语言通过文件指针来操作文件。文件指针是一个指向
FILE
结构体的指针。FILE
结构体是在<stdio.h>
头文件中定义的,它包含了文件操作所需的各种信息。 - 例如,文件指针的定义形式为
FILE *fp;
,这里fp
就是文件指针变量。这个FILE
结构体内部包含了文件当前的读写位置、缓冲区信息、文件的状态标志(如文件是否已到达末尾、是否发生错误等)等重要信息。
- C语言通过文件指针来操作文件。文件指针是一个指向
-
文件的打开与关闭操作
- 文件打开函数
fopen
- 语法:
FILE *fp = fopen("文件名","打开模式");
。 - “文件名”参数指定要打开的文件名称。如果文件不在当前目录下,需要提供完整的路径。例如,在Windows系统下,
"C:\\Users\\user\\Documents\\data.txt"
指定了C盘用户文档文件夹下的data.txt
文件;在Linux系统下,"/home/user/data.txt"
指定了用户主目录下的data.txt
文件。 - “打开模式”决定了文件打开后的操作方式。常见的打开模式有:
"r"
:只读模式打开文本文件。如果文件不存在,fopen
函数返回NULL
,表示打开失败。"w"
:只写模式打开文本文件。如果文件不存在,会创建新文件;如果文件存在,会清空文件内容。"a"
:追加模式打开文本文件。如果文件不存在,会创建新文件;如果文件存在,会在文件末尾添加内容。- 对于二进制文件,相应的模式有
"rb"
、"wb"
、"ab"
,分别表示二进制文件的只读、只写、追加模式。
- 例如,要打开一个当前目录下的文本文件
test.txt
用于读取,可以这样写:
这里使用FILE *fp = fopen("test.txt","r"); if(fp == NULL) { perror("文件打开失败"); return 1; }
perror
函数来输出错误信息,当fp
为NULL
时,perror
会输出错误原因。
- 语法:
- 文件关闭函数
fclose
- 语法:
fclose(fp);
,其中fp
是通过fopen
函数打开文件得到的文件指针。 - 关闭文件的重要性在于确保缓冲区中的数据被正确写入文件,防止数据丢失。同时,及时关闭文件可以释放文件相关的系统资源,使系统能够更好地管理文件。例如,如果程序频繁打开文件而不关闭,可能会导致系统资源耗尽,影响其他程序的运行。
- 语法:
- 文件打开函数
-
文件的读写操作
- 字符读写函数
fgetc
和fputc
fgetc
函数- 语法:
int ch = fgetc(fp);
,其中fp
是文件指针。 - 功能:从文件指针
fp
指向的文件中读取一个字符。读取成功后,返回读取到的字符的ASCII码值。如果遇到文件末尾或者读取错误,返回EOF
(EOF
是在<stdio.h>
中定义的常量,通常值为 - 1)。 - 例如,以下代码可以读取一个文本文件的内容并输出到控制台:
FILE *fp = fopen("input.txt","r"); int ch; while((ch = fgetc(fp))!= EOF) { putchar(ch); } fclose(fp);
- 语法:
fputc
函数- 语法:
fputc('A',fp);
,这里将字符'A'写入文件指针fp
指向的文件中。 - 功能:将一个字符写入文件。如果写入成功,返回写入的字符;如果写入失败,返回
EOF
。
- 语法:
- 字符串读写函数
fgets
和fputs
fgets
函数- 语法:
char str[100]; fgets(str, sizeof(str),fp);
。 - 功能:从文件中读取一行字符串。它会读取最多
sizeof(str) - 1
个字符(因为要预留一个位置给字符串结束符'\0'
)到str
数组中。 - 返回值:如果读取成功,返回
str
(即读取到的字符串的首地址);如果遇到文件末尾或者读取错误,返回NULL
。例如,以下代码可以读取文件中的每一行并打印:FILE *fp = fopen("lines.txt","r"); char line[256]; while(fgets(line, sizeof(line),fp)!= NULL) { printf("%s",line); } fclose(fp);
- 语法:
fputs
函数- 语法:
fputs("Hello World",fp);
,将字符串“Hello World”写入文件(不包括字符串结束符'\0'
)。 - 功能:将一个字符串写入文件。如果写入成功,返回一个非负整数;如果写入失败,返回
EOF
。
- 语法:
- 格式化读写函数
fscanf
和fprintf
fscanf
函数- 语法:
fscanf(fp,"%d %s", &num, str);
,从文件中按照指定格式读取数据。 - 功能:类似于
scanf
函数,用于从文件中读取数据。可以读取整数、浮点数、字符串等按照指定格式组合的数据。 - 返回值:如果成功读取了指定格式的数据,返回成功读取的项数;如果遇到文件末尾或者读取错误,返回
EOF
。
- 语法:
fprintf
函数- 语法:
fprintf(fp,"%d %s", num, str);
,将数据按照指定格式写入文件。 - 功能:类似于
printf
函数,用于将数据写入文件。可以将整数、浮点数、字符串等按照指定格式组合的数据写入文件。 - 例如,若有一个结构体用于存储学生信息,包括学号和姓名,可以使用
fscanf
从文件中读取学生信息,使用fprintf
将学生信息写入文件:struct Student { int id; char name[50]; }; struct Student s; FILE *fp = fopen("students.txt","r"); fscanf(fp,"%d %s", &s.id, s.name); fclose(fp); fp = fopen("students.txt","w"); fprintf(fp,"%d %s", s.id, s.name); fclose(fp);
- 语法:
- 块读写函数
fread
和fwrite
fread
函数- 语法:
fread(&struct_var, sizeof(struct_var), 1,fp);
,用于从文件中读取二进制数据块。 - 功能:从文件中读取一个数据块,数据块大小为
sizeof(struct_var)
,读取的数量为1,存储到&struct_var
地址处。常用于读取二进制文件中的结构体、数组等数据。
- 语法:
fwrite
函数- 语法:
fwrite(&struct_var, sizeof(struct_var), 1,fp);
,用于将二进制数据块写入文件。 - 功能:将
&struct_var
地址处的数据块(大小为sizeof(struct_var)
)写入文件,写入数量为1。例如,将一个结构体数组写入二进制文件:struct Data { int value; }; struct Data data_array[10]; FILE *fp = fopen("data.bin","wb"); fwrite(data_array, sizeof(data_array), 1,fp); fclose(fp);
- 语法:
- 字符读写函数
-
文件的定位操作
ftell
函数- 语法:
long offset = ftell(fp);
。 - 功能:获取文件指针
fp
的当前位置,返回值是一个长整型,表示文件指针相对于文件开头的偏移量(以字节为单位)。例如,在读取文件过程中,可以通过ftell
函数记录当前读取位置。
- 语法:
fseek
函数- 语法:
fseek(fp, offset, origin);
,其中fp
是文件指针,offset
是偏移量(可以是正、负或零),origin
是起始位置,有SEEK_SET
(文件开头)、SEEK_CUR
(文件当前位置)、SEEK_END
(文件末尾)三种选择。 - 功能:用于移动文件指针的位置。例如,
fseek(fp, 10L, SEEK_SET);
会将文件指针从文件开头向后移动10个字节。这在随机读写文件时非常有用,比如在文件中间插入或修改数据。
- 语法:
rewind
函数- 语法:
rewind(fp);
。 - 功能:将文件指针重新定位到文件开头。当需要重新读取一个已经打开的文件的内容,或者对文件进行多次读写操作每次从开头开始时,可以使用
rewind
函数。例如,在一个文件中先读取数据用于统计,然后再读取数据用于打印,就可以在第二次读取前使用rewind
函数将文件指针移回开头。
- 语法:
教材学习中的问题和解决过程
问题1:打开文件必须用指针吗
答:在C语言中,打开文件时通常会使用文件指针,但并不是绝对必须的。以下是一些相关的要点:
-
使用指针的原因:文件指针(
FILE*
类型)用于指向打开的文件。通过这个指针,程序可以读取或写入文件的内容。使用指针可以方便地管理文件操作,例如读取、写入、关闭文件等。 -
示例代码:
FILE *file = fopen("example.txt", "r"); if (file == NULL) { perror("Error opening file"); return -1; } // 文件操作... fclose(file);
-
没有指针的情况:在某些高层次的编程语言中,或是使用特定的库,可能不需要直接处理文件指针。例如,Python中可以直接通过文件对象进行操作,不需要显示的指针类型。
-
抽象封装:在C语言中,虽然文件操作依赖指针,但有些高级的抽象(如类或结构体)可以封装这些操作,间接地使用文件指针。
问题2:fopen函数中不同的文件打开模式(如"r"、"w"、"a"等)是什么意思?它们之间有什么主要的区别?
答:
在C语言中,fopen
函数用于打开文件,并允许以不同的模式来读取或写入数据。每种打开模式具有不同的含义和行为。以下是一些常用的文件打开模式及其主要区别:
常用文件打开模式
-
"r"
(只读模式):- 打开一个现有的文件进行读取。
- 文件指针指向文件的开头。
- 如果文件不存在,
fopen
返回NULL
。
-
"w"
(写入模式):- 创建一个新文件用于写入(如果文件已经存在,则会被截断为零长度,也就是清空文件)。
- 文件指针指向文件的开头。
- 如果文件不存在,自动创建新文件。
-
"a"
(追加模式):- 打开一个现有的文件用于写入,并将数据附加到文件末尾。
- 如果文件不存在,则创建新文件。
- 文件指针指向文件的末尾。
-
"r+"
(读写模式):- 打开一个现有的文件以便读取和写入。
- 文件指针指向文件的开头。
- 如果文件不存在,
fopen
返回NULL
。
-
"w+"
(读写创建模式):- 创建一个新文件用于读取和写入(如果文件已存在将被截断)。
- 文件指针指向文件的开头。
-
"a+"
(读写追加模式):- 打开一个文件用于读取和写入,并将数据附加到文件末尾。
- 如果文件不存在,将创建新文件。
- 文件指针指向文件的末尾。
主要区别
-
文件存在性:
"r"
、"r+"
模式要求文件必须存在;如果不存在,打开失败。"w"
、"w+"
、"a"
、"a+"
模式会创建新文件,如果文件不存在。
-
数据处理方式:
"w"
和"w+"
会清空已有文件的内容,而"a"
和"a+"
则会保留文件内容,将新数据追加到文件末尾。
-
读写权限:
"r"
、"r+"
只有读取权限,不能写入。"w"
、"w+"
、"a"
、"a+"
允许写入,有些模式还允许读取。
示例代码
以下是一个示例,展示如何使用这些模式:
#include <stdio.h>
int main() {
// 只读
FILE *file1 = fopen("example.txt", "r");
if (file1 == NULL) {
perror("Error opening file for reading");
}
// 写入(清空文件)
FILE *file2 = fopen("example.txt", "w");
if (file2 == NULL) {
perror("Error opening file for writing");
}
// 追加
FILE *file3 = fopen("example.txt", "a");
if (file3 == NULL) {
perror("Error opening file for appending");
}
// 读写
FILE *file4 = fopen("example.txt", "r+");
if (file4 == NULL) {
perror("Error opening file for reading and writing");
}
// 关闭文件
fclose(file1);
fclose(file2);
fclose(file3);
fclose(file4);
return 0;
}
问题3:在处理多个文件时,是否可以同时打开多个文件指针?如果可以,如何确保同时进行的文件操作不会互相干扰?
答:
在C语言中,可以同时打开多个文件指针,这对于处理多个文件是非常常见的情况。例如,程序可以同时读取一个文件并写入另一个文件。在操作多个文件时,有几件事需要注意,以确保文件操作互不干扰:
同时打开多个文件指针
你可以简单地通过多次调用fopen()
来打开多个文件。每个打开的文件都会返回一个独立的FILE*
指针。例如:
#include <stdio.h>
int main() {
FILE *file1 = fopen("file1.txt", "r");
FILE *file2 = fopen("file2.txt", "w");
if (file1 == NULL || file2 == NULL) {
perror("Error opening files");
return -1;
}
// 处理文件...
fclose(file1);
fclose(file2);
return 0;
}
确保操作不互相干扰
-
使用独立的文件指针:每个文件都通过单独的
FILE*
指针进行操作。在写入或读取文件时,确保使用正确的指针。例如,不要在写入file2
时错误地使用file1
。 -
检查返回值:在每次文件操作后确认操作是否成功,例如检查
fgets()
、fprintf()
等函数的返回值,以确保操作没有出错。 -
控制文件位置:利用
fseek()
和ftell()
等函数管理每个文件的读取和写入位置,确保在通用操作中不产生混淆。 -
正确关闭文件:在完成所有文件操作后,应确保使用
fclose()
关闭每个文件。这不仅释放了资源,还确保所有缓冲区数据已正确写入文件。 -
防止竞争条件:在多线程程序中处理文件时,确保对文件的访问是线程安全的。这可以通过互斥锁等机制来实现,以避免多个线程同时对同一个文件进行操作。
示例
下面是一个简单的示例,展示如何同时读取一个文件并向另一个文件写入数据,而不产生干扰:
#include <stdio.h>
int main() {
FILE *inputFile = fopen("input.txt", "r");
FILE *outputFile = fopen("output.txt", "w");
if (inputFile == NULL || outputFile == NULL) {
perror("Error opening files");
return -1;
}
char buffer[100];
// 读取 input.txt 的内容并写入 output.txt
while (fgets(buffer, sizeof(buffer), inputFile) != NULL) {
fputs(buffer, outputFile); // 将读取的内容写入 output.txt
}
// 关闭文件
fclose(inputFile);
fclose(outputFile);
return 0;
}
在这个例子中,inputFile
和outputFile
是两个独立的文件指针,用于同时读写不同的文件。它们的操作彼此独立,不会干扰。
基于AI的学习