文件介绍
计算机中有内存和外存,内存用于临时存储数据关机后消失,而外存关机后则会一直保留数据。而文件就保存在磁盘(硬盘上)。在程序设计中一般文件有程序文件、数据文件。
程序文件
程序文件包括源程序文件(.c后缀文件),目标文件(Windows环境下的.obj文件),可执行程序(Windows环境下的.exe文件)。
数据文件
文件读取的是程序上的数据,不一定就是程序,在一般时候写代码是将结果输入输出在终端上,即用键盘输入,然后再终端上(显示器)输出显示,有时写代码也可以将结果写在文件中保存在磁盘上,当需要在读取的时候再将其读取到内存中使用。
每个文件存在唯一标识,这个标识就是文件名,文件名:文件路径+文件名主干+文件名后缀,
二进制文件和文本文件
根据数据文件组成形式,分为文本文件和二进制文件数据在内存中以二进制形式存储,不加载到外存,就是二进制文件
如果要在外存中以ASCII编码形式存储,就需要在存储前转换。以ASCII字符形式存储的是文本文件。
文件的打开和关闭
流
程序的数据需要输出到各种外部设备中,也需要从外部设备中获取数据,由于不同的外部设备中的操作方式各异,于是就有了“流”这一抽象概念,这个“流”可以从字面上理解,类似水流的一种形式。在C语言中对画面、键盘、文件都是用“流”进行的。
标准流
C语言程序运行中,默认打开了三个流:
stdin:标准输入流,在大多数的环境中从键盘输入,scanf就是从标准输入流中读取的数据。
stdout:标准输出流,大多数环境中输出至显示器展现,printf函数就是将信息输出到标准流。
stder:标准错误流,大多数环境中将信息输出到显示器展现。
这三者都是FILE*指针类型,即文件指针。
文件指针
每一个正在使用的文件都在内存中开辟一个相应的文件信息区,用来存放相关的信息,这些信息保存在一个结构体变量中,这个结构体是由系统声明的。定义一个FILE类型指针变量,可以使该变量指向某个文件的文件信息区,通过该信息区就能够访问该文件。换言之,就是通过FILE类型指针可以访问指定文件。
文件的操作
打开和关闭
文件的正常使用顺序:打开文件→使用文件→关闭文件。
ANSI C规定在编译文件时使用fopen函数打开文件,fclose函数来关闭文件,例如:
#include<stdio.h>
int main()
{
FILE* file = fopen("text.txt","w");//文件名,打开方式
///
int fclose(file);
return 0;
}
如果fopen函数打开一个未创建过的文件,那么这个文件将会以函数中显示的文件名保存在当前目录中。而文件有多种打开方式。
“r” | 读:打开文件进行输入操作。该文件必须存在。 |
“W” | 写:为输出操作创建一个空文件。如果已存在同名文件,则丢弃其内容,并将该文件视为新的空文件。 |
“一个” | 附加:打开文件以在文件末尾输出。输出操作始终在文件末尾写入数据,并展开文件。重新定位操作(fseek、fsetpos、rewind)将被忽略。如果文件不存在,则创建该文件。 |
“r+” | 阅读/更新:打开要更新的文件(用于输入和输出)。该文件必须存在。 |
“W+” | 写入/更新:创建一个空文件并打开它进行更新(用于输入和输出)。如果同名文件已存在,则其内容将被丢弃,并将该文件视为新的空文件。 |
“A+” | 追加/更新:打开要更新的文件(用于输入和输出),所有输出操作都将在文件末尾写入数据。重新定位操作(fseek、fsetpos、倒带)会影响下一个输入操作,但输出操作会将位置移回文件末尾。如果文件不存在,则创建该文件。 |
(来自:fopen - C++ 参考 (cplusplus.com))
想要如何使用,需要用对应的方式打开才行。
而fclose函数关闭一个打开的文件。成功时返回0,失败时返回EOF。
文件的读写
顺序读写
函数名称 | 作用 | 返回值 | 适用于 |
---|---|---|---|
fputc | 向文件写入一个字符 | int ,成功时返回写入的字符,失败时返回EOF | 所有输出流 |
fgetc | 从文件读取一个字符 | int ,成功时返回读取的字符,失败或到达文件末尾时返回EOF | 所有输入流 |
fputs | 向文件写入一个字符串(不包括结尾的空字符'\0') | int ,成功时返回非负值,失败时返回EOF | 所有输出流 |
fgets | 从文件读取一行(包括换行符,如果有的话) | char* ,成功时返回指向读取字符串的指针,失败或到达文件末尾时返回NULL | 所有输入流 |
fprintf | 向文件写入格式化的数据 | int ,成功时返回写入的字符数(不包括结尾的空字符'\0'),失败时返回EOF | 所有输出流 |
fscanf | 从文件读取格式化的数据 | int ,成功时返回成功匹配并赋值的输入项的数量,失败或到达文件末尾时返回EOF | 所有输入流 |
fwrite | 以二进制形式向文件写入数据块 | size_t ,成功时返回写入的元素数量,失败时返回0 | 文件 |
fread | 以二进制形式从文件读取数据块 | size_t ,成功时返回读取的元素数量,可能小于请求的数量(如果到达文件末尾或发生错误) | 文件 |
以下是一些样例
fputs/fputc函数使用样例:
//先从数组中读取字符串到文件中
#include<stdio.h>
int main()
{
char arr[] = " hello word ";
FILE* file = fopen("test.txt","w");//如果是w即是写,fgetc无效
if (file == NULL)
{
perror("fopen");
return 1;
}
for (char b = 'a'; b <= 'z'; b++)
fputc(b, file);// int fputc(int character, FILE * stream);//向文件写入一个字符
fputs(arr,file);//int fputs ( const char * str, FILE * stream );
//
fclose(file);
file = NULL;
return 0;
}
这是文件得到的结果
fgets/fgetc使用样例:
//再从文件中读到字符串
#include <stdio.h>
int main()
{
char a[] = {"h"};
FILE* pf=fopen("test.txt","r");
fgets(a,8,pf);
//另一种写法
//for (size_t i = 0; i<10; i++)
// {
// a[i] = fgetc(pf);
//}
fclose(pf);
pf = NULL;
return 0;
}
此时a数组中的元素:
fprintf函数示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct ql
{
char ar[10];
int a;
int b;
};
int main()
{
FILE* file = fopen("text.txt","w");
FILE* a = file;
char q[] = "this is string\n";
printf("%s", fgets(q, 2, a)); //如果在读取任何字符之前发生这种情况,则返回的指针为NULL
struct ql p = {"nihaonihao",7,20};//结构体变量赋值
fprintf(file,"%s %d %d",p.ar,p.a,p.b);//将指针变量p指向的元素放在文件指针file指向的文件里
fclose(file);
file = NULL;
return 0;
}
fscanf函数使用示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* file = fopen("text.txt","r");
char q[] = { "this is string\n" };
fscanf(file, "%s",q);
fclose(file);
file = NULL;
return 0;
}
fwrite函数示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* file = fopen("text.txt","w");
char q[] = { "this is string\n" };
fwrite(q,sizeof(char),strlen(q),file);
fclose(file);
file = NULL;
return 0;
}
此时的文件显示的是
然后再用fread读出到另外一个数组中
int main()
{
FILE* file = fopen("text.txt","rb");
char q[] = { "this is str'\0'ng\n" };
char w[] = { "xxxxxxxxxxxxxxxx" };
fread(w, sizeof(char), strlen(q), file);
随机读写
fseek
int fseek(FILE *stream, long offset, int whence);
根据文件指定 的位置和偏移量来定位指针。在向读取文件时,每读取或者写入一个字符后,文件指针就会向后移动一个字符(可以理解为光标向后移动一个字符)。
来看个fseek的错误使用案例:
int main()
{
FILE* file = fopen("text.txt", "wb");
char q[] = { "this is strng\n" };
char w[] = { "xxxxxxxxxxxxxxxx" };
fputs("qwer", file);
int ret=fseek(file, 3,w );
printf("%d",ret);
fclose(file);
file = NULL;
return 0;
}
这里,错误地将 w
(一个指向字符数组 "xxxxxxxxxxxxxxxx"
的指针)作为 whence
参数传递给了 fseek
。因为 w
是一个指向字符的指针,其值(即地址)很可能不是一个有效的 whence
值(即不是 SEEK_SET
、SEEK_CUR
或 SEEK_END
之一)。这导致 fseek
的行为未定义,很可能是导致程序崩溃的原因。SEEK_SET
(文件开头)、SEEK_CUR
(当前位置)、或SEEK_END
(文件末尾)。
int main()
{
FILE* file = fopen("text.txt", "wb");
char q[] = { "this is strng\n" };
char w[] = { "xxxxxxxxxxxxxxxx" };
fputs("qwer", file);
int ret=fseek(file, 3,w );
fputs("df",file);
printf("%d",ret);
fclose(file);
file = NULL;
return 0;
}
ftell
ftell(FILE*stream);
用于获取当前文件位置指示器(即文件指针)相对于文件开头的偏移量。这个函数通常与 fseek
函数一起使用,以实现对文件内容的随机访问。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* file = fopen("text.txt", "rb");
fseek(file,0,SEEK_END);//定位到文件最后的位置
long size = ftell(file);
printf("%d",size);
fclose(file);
file = NULL;
return 0;
}
我们可以配合fseek函数来计算出文件中的字符长度。
rewind
void rewind(FILE*stream);
让指针回到文件起始位置。这里就不在多说了。
文件读取结束的判定
在这里就需要使用feof函数
int feof(FILE*stream);
stream
是指向FILE
对象的指针,该对象标识了要检查的文件流。- 如果已经到达文件末尾(EOF),则返回非零值(通常是 1)。
- 如果没有到达文件末尾,则返回 0。
int main()
{
FILE* file = fopen("text.txt", "rb");
char q[] = { "this is strng\n" };
char w[] = { "xxxxxxxxxxxxxxxx" };
printf("%c\n", fgetc(file));
printf("%c\n", fgetc(file));
printf("读取两个字符时返回的值%d\n", feof(file));;
printf("%c\n", fgetc(file));
printf("%c\n", fgetc(file));
printf("%c\n", fgetc(file));
printf( "当读取到最后字符后的%d\n", feof(file));;
fclose(file);
file = NULL;
return 0;
}
文件缓冲区
ANSI标准采用“缓冲文件系统”处理数据文件的,缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存到磁盘输出数据,要先向”文件缓冲区“输送,到”文件缓冲区“装满时,才输送到磁盘中,相反程序数据区要调用磁盘数据也要先经过”文件缓冲区“,缓冲区的大小由C编译器决定。大致示意图:
那么就用到fflush函数来刷新缓冲区
代码来模拟一下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<Windows.h>
int main()
{
FILE* file = fopen("text.txt", "w");
fputs("hello word ",file);
printf("写数据中...\n");
Sleep(10000);
fflush(file);
Sleep(10000);
fclose(file);
printf("写入完成");
file = NULL;
return 0;
}
以上就是我对C语言文件这一块的学习,希望又能够帮到你的地方,也欢迎各位来补充指正其中的不足。