引言
C语言提供了一系列的标准库函数,用于执行文件操作。这些函数允许程序员在他们的程序中创建、打开、读取、写入和关闭文件等。这意味着你可以使用C语言来处理磁盘上存储的数据。
文件的基本概念
- 文件可以将数据进行持久化的保存。如果没有文件,我们写的数据就存储在电脑的内存中,如果程序退出,内存回收,数据就会丢失。
- 文件分为程序文件和数据文件。程序文件包括源程序文件(.c)目标文件(.obj)可执行程序(.exe)。数据文件用于存储与特定应用程序、项目或用户活动相关的数据。
- 文件名:一个文件要有一个唯一的文件标识,以方便用户识别或者引用。文件名包括三部分:文件路径+文件名主干+文件后缀
- 根据数据的组织形式,数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制形式进行存储,如果不加转换的输出到外存,就是二进制文件。如果要求在外存上以ASCII码形式存储,则需要在存储前转换。以ASCII字符形式存储的文件就是文本文件。
文件的打开与关闭
流与标准流
在计算机科学中,文件流(file stream)是指对数据流的抽象,用于在程序和存储设备之间传输数据。它提供了一种统一的接口来处理输入和输出操作。通常情况下,文件流与一个特定的文件关联,并且可以是只读、只写或者可读写模式。
当你打开一个文件进行读取或写入时,你实际上是创建了一个到该文件的流。这个流允许你按照顺序从头到尾地处理文件内容,就像水从管道中通过一样。
标准流(standard streams)则是预定义的输入/输出接口,在大多数环境中都有三种基本类型:
1. 标准输入 (stdin): 这通常代表键盘输入或另一个程序的输出。
2. 标准输出 (stdout): 这通常代表屏幕显示或者可以重定向到其他程序或文件。
3. 标准错误 (stderr): 用于报告错误消息,默认情况下也会显示在屏幕上但可以被重定向。
这些概念最初来源于Unix系统,但现在广泛应用于各种不同类型的操作系统中。例如,在C语言及其衍生语言如C++、Python等中都存在类似概念。
使用这些标准流能够帮助我们编写更加灵活和可移植性强的代码。因为它们使得我们无需修改代码就能将信息发送至不同目标(比如:将原本打印至控制台界面上信息改为保存至某个日志文件)。
文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息。这些信息被保存在一个结构体变量中,该结构体类型是由系统声明的,取名为FILE。
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
一般通过一个FILE指针来维护这个FILE结构的变量 FILE* pf; 定义pf是一个指向FILE类型的指针变量。可以使FILE指向某个文件的文件信息区。通过该文件信息区中的信息就能访问该文件。也就是说,通过文件指针能够间接找到与它关联的文件。
文件的打开与关闭
打开文件 ----> 读写文件 ---->关闭文件
ANSIC规定用fopen函数来打开文件,fclose来关闭文件
//打开文件
FILE* fopen(const char* filename,const char* mode);
//关闭文件
int fclose(FILE* stream);
mode 表示文件的打开模式,以下是常见的文件打开模式
举一个小栗子ovo
#include <stdio.h>
int main()
{
FILE* pf;
pf=fopen("myfile.txt","w");//打开文件
if(pf != NULL)
{
fputs("example",pf);//文件处理
fclose(pf);//关闭文件
}
return 0;
}
文件的顺序读写
文件的顺序读写是指按照文件中数据的存储顺序,从头到尾依次进行读取或写入操作。这种方式通常是最高效的访问模式,因为它可以最大限度地减少磁盘寻道时间和缓冲区管理开销。
在顺序读写过程中:
- 顺序读取:程序开始时通常会从文件的起始位置(第一个字节)开始,然后逐步向前移动直至文件末尾。每次读取操作都紧接着上一次读取结束的位置继续往下读。
- 顺序写入:与顺序读类似,但方向相反。程序会从文件起始位置开始写数据,并且随着数据不断被写入,指针也会相应地向前移动。
以下是一些顺序读写函数介绍
fgetc
适用于所有输入流(标准输入流+文件输入流)的字符输入函数
Int fgetc(FILE* stream);
从流里获取字符
fputc
适用于所有输出流的字符输出函数
Int fputc(int character,FILE* stream);
将字符写入流
fgets
适用于所有输入流的文本行输入函数
char* fgets(char* str, int num, FILE*stream)
从stream读取最多num-1个字符放进str,最后一个位置放\0
fputs
适用于所有输入流的文本行输出函数
int fputs(const char* str,FILE*stream)
将str指向的c字符串写入stream
fscanf
适用于所有输入流的格式化输入函数
int fscanf(FILE*stream,const char*format,…);
从stream里读取格式化数据
fprintf
适用于所有输出流的格式化输出函数
int fprintf(FILE*stream,const char*format,…);
将格式化数据写入流
fread
适用于文件输入流的的二进制输入
size_t fread(void*ptr,size_t size,size_t count, FILE* stream);
从流中读取一个由count个元素组成的数组,每个元素的大小为size字节,将它们存储在ptr指定的内存块中
fwrite
适用于文件输出流的二进制输出
size_t fwrite(const void* ptr,size_t size, size_t count,FILE*stream);
将由count元素组成的数组(每个元素的大小为size字节),从ptr所指向的内存块写入到流中的当前位置。
举一些栗子ovo
//拷贝文件
int main()
{
FILE* pfread = fopen("C:\\Users\\Lenovo\\Desktop\\data.txt", "r");
if (pfread == NULL)
{
perror("fopen->data.txt");
return 1;
}
FILE* pfwrite = fopen("C:\\Users\\Lenovo\\Desktop\\data_copy.txt", "w");
if (pfwrite == NULL)
{
perror("fopen->data.txt");
return 1;
}
int ch = 0;
while (ch = fgetc(pfread) != EOF)
{
fputc(ch, pfwrite);
}
fclose(pfread);
fclose(pfwrite);
pfread = NULL;
pfwrite = NULL;
return 0;
}
//fread 二进制输入函数 fwrite二进制输出函数
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan",20,90.5 };
FILE* pf = fopen("C:\\Users\\Lenovo\\Desktop\\data.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fwrite(&s, sizeof(s), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { 0 };
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
fprintf(pf, "%s %d %f", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
本次关于文件操作的介绍到此告一段落啦!!下一次我将介绍文件的随机读写以及文件读取结束的判定的相关知识。求赞求赞ovo!!