文件操作(下)
🙈专题:C语言文件操作
⛺作者:暴躁小程序猿
🏖️个人简介:双非本科大二小菜鸟一枚,每天分享自己的收获,希望大家一起进步
文章目录
一、scanf,fscanf,printf,fprintf函数介绍
二、sscanf函数与sprintf函数
2.1sscanf函数的定义
sscanf函数的功能是从一个字符串中格式化读取数据。
与scanf函数相比较:
sscanf是在scanf函数的基础上多了一个参数,const char*buffer表示要格式化读取数据的字符串,用法也和scanf函数相似。
2.2sprintf函数
sprintf函数的功能是将格式化的数据转换成字符串。
sprintf函数和printf函数比较:
sprintf函数相比printf函数多了一个char*buffer参数,这个参数是存放格式化读取获得的数据的一个字符串。
2.3 sprintf函数的使用
代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int age;
float f;
};
int main()
{
//测试sprintf函数
struct S s = { "Hello",10,5.5 };
char ch[10] = { 0 };
sprintf(ch, "%s %d %f", s.arr, s.age, s.f);
printf("%s\n", ch);
return;
}
2.4 sscanf函数的使用
代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int age;
float f;
};
int main()
{
struct S s = { "Hello",10,5.5f};
struct S temp = { 0 };
char buff[100] = { 0 };
sprintf(buff, "%s %d %f", s.arr, s.age, s.f);
printf("%s\n", buff);
//测试sscanf函数
sscanf(buff, "%s %d %f", temp.arr, &(temp.age), &(temp.f));
printf("%s %d %f", temp.arr, temp.age, temp.f);
return 0;
}
三、文件的随机读取
3.1什么是随机读取?
相比于我们之前学的文件的顺序读取,我们只能从文件的第一个数据开始读取,然后按照顺序一个一个读下去,但是我们如果想直接从一个位置开始读取就办不到,这里我们就要考虑文件的随机读取。我们可以用文件指针来说明:
如果顺序读取我们就一个接一个读取,文件指针读取一个数据向后移一个,但是随机读取就是说我们直接读取c,然后不读取a和b,我们该怎么才可以让文件指针直接指到c呢?我们就要用到下面的几个函数:
3.2 fseek函数
3.2.1fseek函数的定义
fseek函数的功能其实就是根据文件指针的位置和偏移量来定位文件指针。
这个函数第一个参数是文件指针也就是一个文件流,第二个是相较于起始位置的偏移量,第三个是起始位置,起始位置又有三种,定义如下:
第一个SEEK_SET表示起始位置是从文件的起始位置开始偏移
第二个SEEK_CUR表示起始位置是从文件指针指向的位置开始偏移
第三个SEEK_END表示起始位置是从文件的末尾开始偏移。
3.3fseek函数的使用
代码如下(示例):
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ( "example.txt" , "wb" );
fputs ( "This is an apple." , pFile );
fseek ( pFile , 9 , SEEK_SET );//从文件的起始位置开始偏移,偏移量是9
fputs ( " sam" , pFile );
fclose ( pFile );
return 0;
}
3.3 ftell函数
3.3.1 ftell函数的定义
ftell函数的作用就是计算当前文件指针相较于起始位置的偏移量。
3.3.2 ftell函数的使用
代码如下(示例):
#include <stdio.h>
int main ()
{
FILE * pFile;
long size;
pFile = fopen ("myfile.txt","rb");
if (pFile==NULL)
perror ("Error opening file");
else
{
fseek (pFile, 0, SEEK_END);
size=ftell (pFile);
fclose (pFile);
printf ("Size of myfile.txt: %ld bytes.\n",size);
}
return 0;
}
3.4 rewind函数
3.4.1 rewind函数的定义
rewind函数的功能就是让文件指针回到文件的起始位置。
四、文本文件和二进制文件
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而以二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。
16进制显示如下:
二进制存储如下:
ASCII码存储如下:
所以说明同一个数据,以ASCII码存储和以二进制文件存储所占字节大小是不同的。
五、文件读取结束的判断
5.1 被错误使用的feof
很多人都会将feof函数使用错误,经常会错误的认为feof函数是用来判断文件是否读取结束的函数,但是实际上这种理解是完全错误的,牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束,feof函数使用的前提是文件已经结束读取了,函数的作用是判断文件是读取失败结束还是遇到文件的结尾结束。
1.文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets );
fgetc判断是否为EOF;
fgets判断是否为NULL;
2.二进制文件的读取结束判断,判断返回值是否小于实际要读的个数;
fread判断返回值是否小于实际要读的个数;
ps:ferror 函数来检测文件读取操作是否出错,当 ferror 函数返回为真时就表示有错误发生。
5.2 文本文件实例
代码如下(示例):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c; // 注意:int,非char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if(!fp)
{
perror("File opening failed");
return EXIT_FAILURE;
}
//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))
puts("I/O error when reading");
else if (feof(fp))
puts("End of file reached successfully");
fclose(fp);
}
5.3 二进制文件实例
代码如下(示例):
#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
double a[SIZE] = {1.,2.,3.,4.,5.};
FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
fclose(fp);
double b[SIZE];
fp = fopen("test.bin","rb");
size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
if(ret_code == SIZE) {
puts("Array read successfully, contents: ");
for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
putchar('\n');
} else {
// error handling
if (feof(fp))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp))
{
perror("Error reading test.bin");
}
}
fclose(fp);
}
六、文件缓存区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
文件缓存区的作用提高了访存速度。
代码如下(示例):
#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
int main()
{
FILE*pf = fopen("test.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
//注:fflush 在高版本的VS上不能使用了
printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
Sleep(10000);
fclose(pf);//注:fclose在关闭文件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}
总结
本篇博客是文件操作的下部分,主要涉及文件的随机读取,讲了sscanf函数,sprintf函数,fseek函数,ftell函数,rewind函数,feof函数,ferror函数,以及文件的缓冲区概念,今天就将文件操作的知识总结完成,希望对大家有帮助,后面即将进入数据结构模块,小猿将持续更新,欢迎大家私信留言,我们明天见~