文章目录
在使用通讯录时,数据在程序结束的一刻销毁,为了数据的持久化,通常会使用文件操作。
1.文件打开与关闭
每个被使用的文件会在内存中创建一个文件信息区,保存文件的相关信息与一个文件结构体中,该结构体是系统声明的名为FILE。通过一个文件指针就能修改文件的信息。
用fopen函数打开文件,并且返回该文件的指针,filename为文件名,mode为文件打开方式
关闭文件用函数fclose,参数是文件名,关闭完置空指针。
打开与关闭的代码
如果打开的文件不在当前项目文件的路径下,需要写一个完整路径,但是斜杠会被当作转义字符,写两个斜杠来表示一个斜杠,防止转义
2.文件顺序读写
1.fputc
fputc,写数据到流中,c是要写的字符,stream是指向流的指针
pf改成stdout,表示标准输出流,输出数据到屏幕上
2.fgetc
fgetc,从流中读取字符,返回该字符的ASCII码值。
用fgetc,ret能得到文件中的数据。
3.fgets
fgets读取文件中的字符串,注意\0也会被当做一个字符读取。n是读取的最大字符数,\0会占一个字符。流中的数据会读取到string字符串中。
4.fputs
fputs直接写一串字符到流中
5.fscanf
fscanf,从流中读取数据,scanf读取数据的流是标准输入流stdin。
从pf的文件流中读取数据到str中。而scanf是从键盘(标准输入流)中读取数据到变量中。
6.fprintf
写数据到流中,printf是写数据到标准输出流,也就是屏幕中。用fprintf能写数据到文件流中。
把str的数据写入到pf的文件流中。而printf是把str的数据写入到屏幕。
7.fread
和fscanf类似,fread读取数据从一个流中
buffer用来存储数据,size是数据类型的字节数,count数据的个数,stream是要读取的流。
8.fwrite
将数据以二进制的形式写到流中
buffer是数据的源头,size数据类型的大小,count数据的个数,stream数据存储的目的地。
如果写的数据是字符,文本是看得懂的。
3.scanf/sscanf/fscanf和print/sprintf/fprintf对比
1.scanf针对标准输入流的格式化输入语句,从标准输入流中读取数据
2.fscanf针对所有输入流的格式化输入语句,也就是说能从文件流中读取数据
3.sscanf则是从字符串中读取数据,针对字符串的格式化输入语句
读取buffer的数据以格式化的形式输入到变量中。
1.printf针对标准输出流的格式化输出语句,一般都输出到屏幕上
2.fprintf针对所有输出流的格式化输出语句,还能输出到文件流中
3.sprintf将格式化的数据输出到字符串中
将参数中的数据输出到buffer中。
4.文件的随机读写
4.1fseek
调整文件指针。stream是打开文件后产生的文件指针,offset是距离初始位置的偏移量,而origin偏移量有三个值
SEEK_CUR是当前指针指向的位置
SEEK_END是文件的末尾位置
SEEK_SET是文件的开始位置
读取文件两次后指针会向后偏移两次,指向了l,但用fseek将文件指针指向文件开始处,再次打印结果为h
4.2ftell
参数是文件指针,返回其中的文件指针偏移量
4.3rewind
将指针调整到最初位置
5.文本文件与二进制文件
字符在内存中以ASCII码的形式存储,数值型数据能以ASCII码形式存储,也能以二进制形式存储。直接以二进制形式存储的文件是二进制文件,加以转换存储的文件是文本文件
10000以二进制形式存储,占用内存大小是4字节,以文本形式存储,占用大小是5字节(分别将每一位上的数字转换成ASCII码存储)。
6.文件读取结束的判定
不能用feof来判断文件是是否读取结束,feof是用来判断文件读取结束时,其结束原因,是遇到文件尾还是读取失败。
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);
}
fgetc在文件读取失败或文件结束时返回EOF,fgets则返回空指针
二进制文件
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);
}
fread函数返回读取到的元素个数,用其返回值与实际要读的元素个数比较。
7.文件缓冲区
系统自动在内存中为每一个使用的文件开辟一块缓存区,将文件数据输入到磁盘中,要先装满缓冲区,缓冲区才会将数据写入到磁盘。从磁盘中读取数据元素同样。
所有在写文件时,如果想对刚刚写下的数据进行操作,必须刷新缓存区,用fflush函数,否则直接对数据进行操作很可能出现错误。
在文件结束时,缓冲区也会自动刷新。
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;
}