✅博客主页:爆打维c-CSDN博客 🐾
🔹分享c语言知识及代码
💠目录
一、文件简介
1. 为什么使用文件?
如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。
2. 什么是文件?
在程序设计中,⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类的)。
程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执行程序(windows 环境后缀为.exe)。
3.文件名
文件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀 例如 c:\code\test.txt 为了⽅便起⻅,⽂件标识常被称为⽂件名。
4.二进制文件和文本文件
数据以二进制数存储在文件里就是二进制文件,以ASCII码存储就是文本文件
下面给出一段代码能更直观的看到二者区别
下列代码将10000和2以二进制存储在文件中,若直接打开test.txt则会出现乱码的情况
我们需要将打开方式换成以二进制编辑器打开
VS上打开⼆进制⽂件的⽅法
可以看到数据确实是以二进制数形式存储到文件中的
二、文件的使用
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名 FILE.
VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
文件指针概念:
FILE* pf; //文件指针变量
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个文件的⽂件信息区(是⼀个结构体变 量)。通过该⽂件信息区中的信息就能够访问该⽂件。通过文件指针变量能够间接找到与它关联的文件。
文件的打开和关闭:
//打开文件——fopen
FILE * fopen ( const char * filename, const char * mode );
//关闭文件——fclose
int fclose ( FILE * stream );
🔹文件的打开模式:
🔹文件的顺序读写
操作实例:
1.写入一个字符
fputc('a', p);
2.写入一个字符串
fputs("abcdefj", p);
!注意此处写入的整行数据会覆盖原数据
3.读取一个字符:
4.读取多个字符
5.读取指定长度的数据
注意 fgets函数的使用,中间的参数num需要给\0 预留一个字节的位置
如果需要读取5个字节的数据则num处应填6
6.写入结构体信息
#include<stdio.h>
struct Stu {
int age;
char id[20];
char name[20];
};
int main(){
struct Stu s = { 13,"20238221044","张三" };
FILE* p = fopen("test.txt", "w");
if (p != NULL) {
fprintf(p, "%d %s %s", s.age, s.id, s.name);
p = NULL;
}
else {
perror("fopen");
return 1;
}
return 0;
}
7.读取文件信息到结构体变量中
#include<stdio.h>
struct Stu {
int age;
char id[20];
char name[20];
};
int main(){
char arr[10] = { 0 };
FILE* p = fopen("test.txt", "r");
if (p != NULL) {
struct Stu s = { 0 };
fscanf(p, "%d %s %s", &s.age, s.id, s.name);
printf("该学生年龄为:%d 学号为:%s 姓名为:%s", s.age, s.id, s.name);
fclose(p);
p = NULL;
}
else {
perror("fopen");
return 1;
}
return 0;
}
运行结果:
8.二进制写入及读取
二进制写入函数——fwrite
二进制读取函数——fread
感兴趣的同学自己打开编译器试着操作一下会更有收获
对比一组函数:
scanf/ fscanf / sscanf
printf / fprintf / sprintf
看到s是不是就会自然而然的想到于字符串有关呢?事实确实如此
大家注意不要把sscanf、sprintf与文件操作函数弄混淆
sscanf:
- int sscanf( const char *buffer, const char *format [, argument ] ... );
- function:将一个字符串转化为格式化数据;
#include<stdio.h>
int main(){
char str[] = "20010606wy"; //定义一个字符串
int day = 0;
char name[10] = { 0 };
sscanf(str, "%d %s", &day,name);
return 0;
}
运行后:
sprintf:
int sprintf( char *buffer, const char *format [, argument] ... );
将一个格式化数据转化为字符串;
#include<stdio.h>
int main(){
char str[20] = { 0 };
int day = 20010606;
char name[5] = "wy";
sprintf(str, "%d %s", day, name);
return 0;
}
运行后:
三、文件的随机读写:
在C语言中,fseek、ftell和rewind是用于文件定位和文件指针操作的函数。
下面将详细介绍这三个函数,并给出一些示例:
fseek函数:
▪️ 功能:用于设置文件指针位置。
▪️ 函数原型:int fseek(FILE *stream, long int offset, int origin);
▪️ 参数:
stream:指向FILE类型的指针,表示要进行定位的文件流。
可以是SEEK_SET(文件开头)、SEEK_CUR(当前位置)或SEEK_END(文件末尾)。offset:long int类型的值,表示相对于origin的偏移量。
origin:用于指定偏移量的起始位置,
▪️ 返回值:
0 表示成功,其他值表示失败。
示例:
FILE *file = fopen("example.txt", "r");
fseek(file, 10, SEEK_SET); // 将文件指针设置到文件开头后的第10个字节处
ftell函数:
▪️函数原型:long int ftell(FILE *stream);
▪️功能:用于获取文件指针的当前位置。
▪️参数:stream:指向FILE类型的指针,表示要获取当前位置的文件流。
▪️返回值:long int类型的值,表示当前位置相对于文件开头的偏移量
示例:
FILE *file = fopen("example.txt", "r");
fseek(file, 10, SEEK_SET);
long int position = ftell(file); // 获取文件指针当前位置
printf("Current position: %ld\n", position);
rewind函数:
▪️函数原型:void rewind(FILE *stream);
▪️功能:用于将文件指针重新设置到文件的开头。
▪️参数:stream:指向FILE类型的指针,表示要重新设置位置的文件流。
▪️返回值:无。
示例:
FILE *file = fopen("example.txt", "r");
fseek(file, 10, SEEK_SET);
rewind(file); // 将文件指针重新设置到文件开头
这些函数可以帮助在文件操作过程中进行定位和指针操作。fseek用于设置文件指针位置,ftell用于获取当前位置的偏移量,而rewind用于将文件指针重新设置到文件开头。这些函数在处理文件时非常有用,可以在文件读写过程中进行灵活的定位和操作。
四、文件读取结束的判定
文件读取结束有两种情况:1.读取过程中出现异常 2.读取到文件末尾;
要找出文件读取是哪个原因,就分为以下情况:
1.文本文件是否结束
判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
• fgetc 判断是否为 EOF .
• fgets 判断返回值是否为 NULL .
2. 二进制文件是否结束
判断返回值是否⼩于实际要读的个数。
• fread判断返回值是否小于实际要读的个数。
🔹对于读取异常的判断,我们考虑判断 ferror() 函数的返回值:
- 若ferrror()为真——异常读取而结束;
- 若feof()为真——正常读取到尾而结束;
feof函数:
在C语言中,feof函数用于检查文件流的文件结束标志,用来判断文件读取结束的原因。
牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。
下面是关于feof函数的详细介绍:
▪️函数原型:int feof(FILE *stream);
▪️功能:用于检查文件流指针所指向的文件是否已经到达文件结尾。
▪️参数:stream为指向FILE类型结构的指针,表示要检查的文件流。
▪️返回值:若到达文件结尾,则返回非零值(1),否则返回零值(0)。
示例:
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
while (!feof(file)) {
char ch = fgetc(file);
if (ch != EOF) {
printf("%c", ch);
} else {
break;
}
}
fclose(file);
在示例中,首先打开一个文件流,并使用feof函数在循环中检查文件是否已经到达结尾。在循环中,每次读取一个字符,并判断是否为文件结束符EOF,如果不是则输出字符。循环直到文件结束标志被检测到或者文件读取出错时终止。
通过使用feof函数,可以检查文件流是否已经到达结尾,帮助程序在处理文件时进行正确的流程控制。需要注意的是,feof函数只能检查文件流的状态,并不能准确判断文件读取操作的成功与否,因此在实际使用中需要结合其他函数进行合理的错误处理。
文本文件的判断:
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen is failed !");
return;
}
int c = 0;
//由于要检查EOF——EOF本质是-1——所以是int
while (c = fgetc(pf) != EOF)
{
putchar(c);
}
//直到while不执行了—读取结束了—判断是什么原因结束的
if (ferror(pf))
{
printf("读取中出现错误\n");
}
else if (feof(pf))
{
printf("读取到文件尾\n");
}
fclose(pf);
pf = NULL;
return 0;
}
二进制文件的判断:
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "rb");
int arr[5] = { 0 };
if (pf == NULL)
{
return;
}
size_t num = fread(arr, sizeof(int), 5, pf);
if (num == 5)
{
//说明全部读取成功
printf("Array read successfully\n");
}
else
{
//说明读取不够指定长度—判断是什么原因
if (ferror(pf))
{
printf("读取中出现错误\n");
}
else if (feof(pf))
{
printf("读取到文件尾\n");
}
}
fclose(pf);
pf = NULL;
return 0;
}