导言:
文件操作是计算机编程中不可或缺的一部分,它涉及到文件的创建、读取、写入和删除等基本操作。本文将探讨文件操作的基本感念和常见的文件操作方式,以帮助读者更好地理解计算机中的文件存储与读写。
目录
正文:
我们在平常写代码时创建的内容和数据都是存放在内存中的,随着程序的关闭这些数据也就会销毁掉了。如果我们想要把数据记录保存下来就需要将数据存放在电脑的硬盘上。c语言中提供了文件操作来帮助我们实现这一操作,而我们想要对文件进行操作就必须要使用文件指针。
一.文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。文件指针是在文件操作中用于指示当前读/写位置的一个概念。它是一个指向文件中某个位置的指针,通过它可以实现对文件的随机访问。文件指针通常用于定位文件中的读/写位置,并在读写操作中进行移动。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.我们只需知道FILE是一个结构体类型,不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中信息,使用者不必关心细节。一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
我们可以创建一个FILE*的指针变量:
FILE* pf;//文件指针变量
二.文件的打开和关闭
我们在使用文件时应该先打开文件,在是使用结束后也应该要关闭文件。
文件的打开: 在C语言中,可以使用fopen
函数来打开一个文件。
fopen
函数的原型如下:
FILE *fopen(const char *filename, const char *mode);
fopen
函数接受两个参数:filename
表示文件路径,可以是相对路径或绝对路径;mode
表示打开方式,常见的打开方式有以下几种:
"r":以只读方式打开文件,文件必须存在。
"w":以写入方式打开文件,如果文件不存在则创建,如果文件存在则清空内容。
"a":以追加方式打开文件,如果文件不存在则创建,如果文件存在则在文件末尾追加内容。
"rb":以二进制只读方式打开文件,文件必须存在。
"wb":以二进制写入方式打开文件,如果文件不存在则创建,如果文件存在则清空内容。
"ab":以二进制追加方式打开文件,如果文件不存在则创建,如果文件存在则在文件末尾追加内容。
"r+":以读写方式打开文件。文件必须存在,否则打开失败。
"w+":以读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则清空文件内容。
"a+":以读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则在文件末尾追加内容。
"r+b"或"rb+":以二进制读写方式打开文件。文件必须存在,否则打开失败。
"w+b"或"wb+":以二进制读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则清空文件内容。
"a+b"或"ab+":以二进制读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则在文件末尾追加内容。
fopen
函数返回一个指向FILE
类型的指针,该指针表示打开的文件。如果文件打开成功,则返回指向文件的指针;如果文件打开失败,则返回NULL
。
实例代码:
FILE* fp = fopen("myfile.txt", "w");//以写的方式打开文件
//如果文件打开失败,打印错误信息
if (fp == NULL) {
perror("fopen");
}
文件的关闭: 在C语言中,可以使用fclose
函数来关闭一个文件。
fclose
函数的原型如下:
int fclose(FILE *stream);
fclose
函数接受一个参数:stream
表示要关闭的文件指针。
fclose
函数用于关闭文件,并释放相关资源。在进行文件操作时,应该在操作完成后及时关闭文件,以避免资源泄露和其他问题。如果文件关闭成功,则返回0;如果文件关闭失败,则返回非0值。
实例代码:
FILE* fp = fopen("myfile.txt", "w");//以写的方式打开文件
//如果文件打开失败,打印错误信息
if (fp == NULL) {
perror("fopen");
}
fcolse(fp);//关闭文件
三.文件的读写操作
1.fgetc
和fputc
:
这两个函数用于读取和写入一个字符。fgetc
函数从文件中读取一个字符,fputc
函数将一个字符写入到文件中。它们的原型如下:
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
fgetc
函数返回读取的字符,如果读取失败或到达文件结尾,则返回EOF
。fputc
函数返回写入的字符,如果写入失败,则返回EOF
。
代码实例:
#pragma warning(disable:4996)
#include <stdio.h>
int main() {
//以写模式打开
FILE* pf1 = fopen("data.txt", "w");
if (pf1 == NULL) {
perror("fopen");
return 1;
}
//写文件
fputc('a', pf1);
fputc('b', pf1);
fputc('c', pf1);
fputc('d', pf1);
// 关闭文件
fclose(pf1);
pf1 = NULL;
//以读模式打开
FILE* pf2 = fopen("data.txt", "r");
if (pf2 == NULL) {
perror("fopen");
return 1;
}
//读文件
int ch = fgetc(pf2);
printf("%c", ch);
ch = fgetc(pf2);
printf("%c", ch);
ch = fgetc(pf2);
printf("%c", ch);
ch = fgetc(pf2);
printf("%c", ch);
// 关闭文件
fclose(pf2);
pf2 = NULL;
return 0;
}
运行之后可以在文件中发现abcd,读的时候也可以读出abcd。
2.fgets和fputs
:
这两个函数用于读取和写入一行字符串。fgets
函数从文件中读取一行字符串,fputs
函数将一个字符串写入到文件中。它们的原型如下:
char *fgets(char *str, int n, FILE *stream);
int fputs(const char *str, FILE *stream);
fgets
函数将读取的字符串存储到str
指向的字符数组中,最多读取n-1
个字符,包括换行符。如果读取成功,则返回str
;如果读取失败或到达文件结尾,则返回NULL
。fputs
函数将str
指向的字符串写入到文件中,如果写入成功,则返回非负值;如果写入失败,则返回EOF
。
具体实例:
#pragma warning(disable:4996)
#include <stdio.h>
int main() {
FILE* pf1 = fopen("data.txt", "w");
if (pf1 == NULL)
{
perror("fopen");
return 1;
}
//写文件
//fputs("hello", pf);
char arr1[] = "hello";
fputs(arr1, pf1);
fputs("world", pf1);
fclose(pf1);
pf1 = NULL;
FILE* pf2 = fopen("data.txt", "r");
if (pf2 == NULL)
{
perror("fopen");
return 1;
}
//读文件
char arr2[100] = {0};
fgets(arr2, 100, pf2);
printf("%s", arr2);
fclose(pf2);
pf2 = NULL;
return 0;
}
运行之后可以在文件中发现helloworld,读的时候也可以读出helloworld。
3.fread
和fwrite
:
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
这两个函数用于读取和写入二进制数据。fread
函数从文件中读取二进制数据,fwrite
函数将二进制数据写入到文件中。它们的原型如下:
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
fread
函数从stream
指向的文件中读取count
个数据块,每个数据块的大小为size
字节,将读取的数据存储到ptr
指向的内存中。如果读取成功,则返回实际读取的数据块数目;如果读取失败或到达文件结尾,则返回小于count
的值。fwrite
函数将ptr
指向的内存中的count
个数据块,每个数据块的大小为size
字节,写入到stream
指向的文件中。如果写入成功,则返回实际写入的数据块数目;如果写入失败,则返回小于count
的值。
具体案例:
#pragma warning(disable:4996)
#include <stdio.h>
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//写文件
FILE*pf1 = fopen("data.txt", "wb");
if (pf1 == NULL)
{
perror("fopen");
return 1;
}
//二进制的写文件
fwrite(arr1, sizeof(arr1[0]), sizeof(arr1)/sizeof(arr1[0]), pf1);
fclose(pf1);
pf1 = NULL;
//读文件
int arr2[10] = { 0 };
FILE* pf2 = fopen("data.txt", "rb");
if (pf2 == NULL)
{
perror("fopen");
return 1;
}
//二进制的读文件
fread(arr2, sizeof(arr2[0]), sizeof(arr2) / sizeof(arr2[0]), pf2);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
fclose(pf2);
pf2= NULL;
return 0;
}
这段代码将arr1数组的内容以二进制的形式存在了文件中,由于是二进制文件,我们根本看不懂文件中的内容,但是可以通过fread将文件读出来并打印到控制台,输出结果1~10。
4.fscanf
和fprintf
:
这两个函数用于格式化的读取和写入数据。fscanf
函数从文件中按照指定的格式读取数据,fprintf
函数按照指定的格式将数据写入到文件中。它们的原型如下:
int fscanf(FILE *stream, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
fscanf
函数按照format
指定的格式从stream
指向的文件中读取数据,并将读取的数据存储到对应的变量中。如果读取成功,则返回成功读取的参数个数;如果读取失败或到达文件结尾,则返回小于成功读取的参数个数。fprintf
函数按照format
指定的格式将数据写入到stream
指向的文件中。如果写入成功,则返回写入的字符数;如果写入失败,则返回负值。
...
是C语言中的可变参数列表,它允许函数接受不定数量的参数。在fscanf
和fprintf
函数中,...
用于接收需要读取或写入的数据。具体来说,fscanf
函数的...
参数应该是指向要读取的变量的指针,而fprintf
函数的...
参数应该是需要写入的数据。
具体实例:
#pragma warning(disable:4996)
#include <stdio.h>
int main() {
FILE* pf1,*pf2;
int num1, num2, sum;
// 打开文件
pf1 = fopen("data.txt", "r");
if (pf1 == NULL) {
perror("fopen");
return 1;
}
// 从文件中读取两个整数,并计算它们的和
fscanf(pf1, "%d %d", &num1, &num2);
sum = num1 + num2;
printf("两个整数的和为:%d\n", sum);
// 关闭文件
fclose(pf1);
pf2 = fopen("data.txt", "w");
if (pf2 == NULL) {
perror("fopen");
return 1;
}
// 将和写入到文件
fprintf(pf2, "%d\n", sum);
// 关闭文件
fclose(pf2);
return 0;
}
该代码可以从文件中先读取两个整数,并将得出的两数之和打印到文件中,但注意这里对一个文件进行了操作会有覆盖作用。
四.文件结束的判定
文件读取结束的判定通常有两种方式:
1.使用返回值:对于大多数文件读取函数,它们的返回值可以用来判断文件是否已经读取到末尾。通常情况下,当函数成功读取到数据时,返回值为读取的字节数或成功读取的数据项个数;当函数读取到文件末尾时,返回值为0或
EOF
(End of File)。因此,可以通过检查返回值是否为0或EOF
来判断文件是否已经读取到末尾。
例如,使用fgets
函数读取一行字符串时,可以通过检查返回值是否为NULL
来判断是否已经读取到文件末尾:
char str[100];
while (fgets(str, sizeof(str), file) != NULL) {
// 处理读取到的字符串
}
2.使用文件指针位置:另一种判断文件读取结束的方式是通过检查文件指针的位置。在C语言中,文件指针指向当前读取或写入的位置。当文件指针指向文件末尾时,表示文件已经读取到末尾。可以使用
feof
函数或fseek
函数来判断文件指针位置。值得注意的是在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而应该应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
feof
函数:判断文件指针位置是否已经到达文件末尾,返回非零值表示已经到达末尾,返回0表示未到达末尾。
while (!feof(file)) {
// 读取文件内容
}
fseek
函数:将文件指针移动到指定位置,可以通过将文件指针移动到文件末尾,然后再判断文件指针位置是否已经到达文件末尾。
fseek(file, 0, SEEK_END);
if (ftell(file) == 0) {
// 文件为空
} else {
// 文件不为空
}
需要注意的是,使用文件指针位置判断文件是否已经读取到末尾时,需要在每次读取操作之后进行判断,否则可能会出现错误的判断结果。而使用返回值判断文件是否已经读取到末尾时,可以在读取操作之后直接进行判断。
总结:
总而言之,文件操作是进行文件读写的重要手段,可以通过文件操作函数来实现对文件的打开、读取、写入、指针移动等操作,并通过错误处理和资源释放来保证操作的正确性和可靠性。希望本文对你有所帮助。