文章目录
一、函数的区别
scanf、fscanf、sscanf的区别
int scanf( const char *format [,argument]... );
int fscanf( FILE *stream, const char *format [, argument ]... );
int sscanf( const char *buffer, const char *format [, argument ] ... );
从这三个函数的声明中可以看出,fscanf和sscanf与scanf相比,多了一个函数参数。
scanf是标准输入流,从终端向程序输入格式化的数据。
fscanf是所有输入流,可以从各种流向程序输入格式化的数据。
sscanf是从字符串中读取格式化的数据。
使用示例:
#include <stdio.h>
int main()
{
int n = 0;
int m = 0;
float f = 0.0f;
fscanf(stdin,"%d %d %f", &n, &m, &f);//C 语言在运行的时候默认打开三个流,stdin,stdout,stderror.
printf("%d %d %f", n, m, f);
return 0;
}
所以对于fscanf只要把它的第一个参数写成stdin,它就可以完成scanf的功能。
int main()
{
char str[] = "1+2+5.5+abcdef";
int m = 0;
int n = 0;
float f = 0.0f;
char str2[10] = { 0 };
sscanf(str, "%d+%d+%f+%s", &m, &n, &f, str2);
printf("%d %d %f %s", m, n, f, str2);
return 0;
}
printf、fprint、sprintf的区别
int printf( const char *format [, argument]... );
int fprintf( FILE *stream, const char *format [, argument ]...);
int sprintf( char *buffer, const char *format [, argument] ... );
printf:标准输出流,把需要的数据输出在屏幕上。
fprintf:所有输出流。
sprintf:将格式化数据转化成字符串
使用示例:
int main()
{
/*char str[100] = { 0 };*/
int n = 5;
int m = 10;
float f = 3.5f;
char arr[10] = "abcdef";
fprintf(stdout, "%d %d %f %s", n, m, f, arr);
return 0;
}
fprintf的第一个参数改成stdout,就可以完成printf的功能。
int main()
{
char str[100] = { 0 };
int n = 5;
int m = 10;
float f = 3.5f;
char arr[10] = "abcdef";
sprintf(str, "%d %d %f %s", n, m, f, arr);
printf("%s", str);
return 0;
}
二、文件的随机读取
1.fseek
根据文件指针的位置和偏移量来定位指针。
int fseek ( FILE * stream, long int offset, int origin );
第三个参数只可以填 SEEK_CUR,SEEK_END,SEEK_SET。
分别是当前位置,文件的末尾,文件的开头。
int main()
{
//test.txt文件里已经写了 abcdef
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
ch = fgetc(pf);
putc(ch, stdout);//a
ch = fgetc(pf);
putc(ch, stdout);//b
//pf每读取一个字符,就会向后移动一位,这时已经指向c了,往后移动两个单位,所以这是pf指向e
fseek(pf, 2, SEEK_CUR);
ch = fgetc(pf);
putc(ch, stdout);//e
fclose(pf);
pf = NULL;
return 0;
}
2.ftell
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
int main()
{
//test.txt文件里已经写了 abcdef
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
ch = fgetc(pf);
putc(ch, stdout);//a
ch = fgetc(pf);
putc(ch, stdout);//b
//pf每读取一个字符,就会向后移动一位,这时已经指向c了,往后移动两个单位,所以这是pf指向e
fseek(pf, 2, SEEK_CUR);
ch = fgetc(pf);
putc(ch, stdout);//e
//pf指向f,距离起始位置5个字节的偏移量
printf("\n%ld", ftell(pf));//5
fclose(pf);
pf = NULL;
return 0;
}
3.rewind
让文件指针回到文件的起始位置
void rewind ( FILE * stream );
int main()
{
//test.txt有数据abcdef
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
fseek(pf, 2, SEEK_SET);
ch = fgetc(pf);//c
putc(ch, stdout);
rewind(pf);
ch = fgetc(pf);
putc(ch, stdout);
return 0;
}
三、文本文件和二进制文件
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
例如:10000
四、文件读取结束的判定
被错误使用的feof
在文件读取过程中,不能使用feof函数的返回值直接用来判断文件是否读取结束。
应当用于文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
正确的使用方法:
文本文件的例子:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int c = 0;
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fopen");
return 1;
}
//fgetc 读取失败或者遇到文件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF)
{
putchar(c);
}
//判断是文件读取结束还是失败
if (feof(fp))
{
puts("End of file reached successfully");
}
else
{
puts("I/O error when reading");
}
}
二进制文件的例子
#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编译系统决定。
具体原因是,从外存中读数据或者向外存中写数据都要借助与操作系统,使用缓冲文件系统是为了提高资源的利用率。