本篇文章介绍c语言中文件的随机读写
fseek()函数的作用是根据文件指针的位置和偏移量定位文件指针
int fseek ( FILE * stream, long int offset, int origin );
参数说明
常量 | 位置 |
SEEK_SET | 文件起始位置 |
SEEK_CUR | 文件指针当前位置 |
SEEK_END | 文件末尾 |
#include
int main()
{
//1. 打开文件
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen()");
return 1;
}
//2.读写文件
//文件数据:20240125 PYSpring 24
//读取一个字符
//将文件指针指到P字符位置
//P的位置相对于起始位置的偏移量为9
fseek(pf,9,SEEK_SET);
int ch = fgetc(pf);
printf("%c\n", ch);
//相对于当前位置的偏移量
//当前指到Y,跳过一个字符,则指到S
fseek(pf,1,SEEK_CUR);
ch = fgetc(pf);
printf("%c\n", ch);
//相对于文件末尾
//offset:-2指到2的位置
fseek(pf,-2,SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);
//3.关闭文件
fclose(pf);
pf = NULL;
return 0;
}
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
ftell()的使用
#include
int main()
{
//1. 打开文件
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen()");
return 1;
}
//2. 读/写文件
// 文件数据:20240125 PYSpring 24
//使用fscanf()读取格式化数据
char student_number[20] = { 0 };
fscanf(pf, "%s ", student_number);
printf("%s\n", student_number);
//获取当前文件指针相对于文件起始位置的偏移量
long int pos_offset = ftell(pf);
printf("%ld\n", pos_offset);
//3. 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
让文件指针回到文件的起始位置
void rewind ( FILE * stream );
rewind()的使用
#include
int main()
{
//1. 打开文件
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen()");
return 1;
}
//2. 读/写文件
// 文件数据:20240125 PYSpring 24
//利用fgets()读取字符串
char student_number[20] = { 0 };
fgets(student_number, sizeof(student_number), pf);
printf("%s\n", student_number);
//获取当前文件的位置
long int pos_offset = ftell(pf);
printf("%ld\n", pos_offset);
//将文件指针回到起始位置
rewind(pf);
pos_offset = ftell(pf);
printf("%ld\n", pos_offset);
//3. 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
根据数据的组织形式,数据文件分为文本文件和二进制文件。
文本文件:将内存的数据存储到外存时,将数据转换为ASCLL码(字符)后,再将数据存储到外存中
二进制文件:将内存的数据直接存储在外存。
字符一律以ASCLL码形式存储,数值型数据既可以用ASCLL形式存储,也可以使用二进制存储。
假设一个数值数据10000,如果以ASCII码的形式存储到外存,则存储10000需要5个字节(5个字符)
如果以二进制形式存储到外存,整型占4个字节,则存储10000需要4个字节。
当想要判断进行某次的读取是否成功时,可根据使用的读/写操作的库函数返回值判断
文件读取结束分为两种情况
4. 正常结束:读取完成,文件指针指到了文件末尾
当想要判断读取是否完成时,可以使用feof()函数进行判断
int feof ( FILE * stream );
返回非0->文件指针指到了文件末尾,数据读取完
返回0 -> 文件指针未达到文件末尾,数据未读取完
int ferror ( FILE * stream );
返回非0 -> 文件在读写过程中发生异常
返回0 -> 文件读写正常
具体例子如下:
对于文本文件的判断
#include
int main()
{
int c; // 注意:int, 非char,要求处理EOF
//1. 打开文件
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//2. 读文件
while ((c = fgetc(pf)) != EOF)
{
printf("%c", c);
}
printf("\n");
//判断是结束的原因
if (ferror(pf))
printf("I/O error when reading\n");
else if (feof(pf))
printf("End of file reached successfully\n");
//3. 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
对于二进制文件的判断
#include
#define ARRAY_SIZE 5
int main()
{
double a[ARRAY_SIZE] = { 1.0,2.0,3.0,4.0,5.0 };
//1. 打开文件
FILE* pf = fopen("data.bin", "wb");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//2. 写文件
fwrite(a, sizeof(a[0]), ARRAY_SIZE, pf);
//3. 关闭文件
fclose(pf);
pf = NULL;
//1. 打开文件
pf = fopen("data.bin", "rb");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//2. 读文件
double b[ARRAY_SIZE] = { 0.0 };
size_t ret_size = fread(b, sizeof(b[0]), ARRAY_SIZE, pf);
if (ret_size == ARRAY_SIZE) //读取完整
{
int i = 0;
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%lf", b[i]);
}
printf("\n");
}
else //结束情况判断
{
if (feof(pf))
printf("Error reading data.bin: unexpected end of file\n");
else if (ferror(pf))
printf("Error reading data.bin\n");
}
//3. 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
ANSIC标准是采用“缓冲文件系统”处理的数据文件。
缓冲文件系统:系统自动地在内存中为程序中每一个使用的文件开辟一块文件缓冲区。
从内存向外存输出数据会先送到内存的输出缓冲区,装满输出缓冲区后才将数据输出到外存。
从外存读取(输入)数据时,从外存文件读取数据输入到输入缓冲区,装满缓冲区才将数据输入到程序数据区(程序变量)。
缓冲区的大小由C编译器决定。
具体代码如下
#include
#include
int main()
{
//1. 打开文件
FILE* pf = fopen("data.txt", "w");
if (NULL == pf)
{
perror("fopen()");
return 1;
}
//2. 写文件
fputs("PYSpring", pf); //将数据写入缓冲区
printf("等待10s\n");
Sleep(10000);
//fflush(pf); //自己强制刷新缓冲区 vs2022无效
//printf("再等待10s\n");
//Sleep(10000);
//3. 关闭文件
fclose(pf); //系统自动刷新缓冲区
pf = NULL;
return 0;
}
因为有缓冲区的存在,c语言在操作文件的时,需要做刷新缓冲区操作
本篇文章介绍文件的随机读写,文本文件和二进制文件的区别,以及文件读取结束的判断, 最后介绍文件缓冲区