c语言的文件操作
什么是文件
磁盘上的文件是文件。 但是在程序设计的过程中,我们一般谈的文件有两种:程序文件、数据文件
程序文件
包括源程序文件(后缀为.c),目标文件(后缀为.obj),可执行程序(后缀为.exe)
数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件
本博客讨论的是数据文件:
文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。 文件名包含3部分:文件路径+文件名主干+文件后缀 例如:c:\code\test.txt 文件标识常被称为文件名
文件指针
每个被使用的的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字、文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中。该结构体类型是有系统声明的,取名为FILE 下图是vs2018编译环境提供的stdio.h头文件中有以下文件类型的声明: 不同编译器包含的的内容不完全相同,但是大同小异。 每当我们打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。 一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
文件指针的定义:
FILE* pf;
文件操作: 定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(结构体变量)。通过该文件信息区就可以访问该文件。也就是说,通过文件指针变量能够找到与它相关联的文件。
文件的类型
根据文件的组织形式,数据文件可以被分为文本文件或者二进制文件 二进制文件: 数据在内存中以二进制形式村删除,并不加转换的输出到外存 文本文件: 外存以ascii码的形式存储。 当然以两种形式存储文件的大小也不一样
文件缓冲区
所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块”文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
文件的打开和关闭**
c语言用两个函数来分别打开和关闭文件:
fopen
FILE *fopen( const char *filename, const char *mode );
返回值: 返回的是打开文件的指针,如果打开失败就返回空指针(NULL) 函数参数
- filename:要打开的文件的文件指针
- mode:一些操作指令,例如:
int main()
{
FILE* pf;
pf = fopen("kksk.txt", "w");
if (pf != NULL)
{
printf("打开文件成功");
fclose(pf);
}
return 0;
}
这样一个文件以写入的方式就打开了,如果我们想要以读的方式打开文件
pf = fopen("kksk.txt", "r");
或者在找到文件的绝对路径
将绝对路径复制到文件指针处,但是记得把’ / ‘替换成’ // ',防止形成转义字符
pf = fopen("D:\\学习资料\\比特教育\\源代码\\Project1\\Project1\\kksk.txt", "r");
文件的顺序读写
字符输入、输出函数
fgetc
适用所有输入流
int fgetc( FILE *stream );
功能: 每次从此刻文件指针指向的位置中读取一个字符。 返回值: 返回的是读取的字符的ACSII码值或者EOF来表明文件读取结束。
int main()
{
FILE* pf;
pf = fopen("D:\\学习资料\\比特教育\\源代码\\Project1\\Project1\\kksk.txt", "r");
if (pf != NULL)
{
printf("打开文件成功");
int ret = 0;
ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
fclose(pf);
}
return 0;
}
如果事先在文件中输入abcd,然后编写程序读取就会有以下结果: 虽然文件中只有四个字符,但是第五次读取时ret的值等于-1(EOF)标志文件结束
fputc
适用于所有输出流
int fputc( int c, FILE *stream );
返回值: 返回的是写入的字符,如果返回的是EOF表面写入失败 函数参数: c:是带写入的字符 stream:是文件指针
文本行输入、输出函数
fgets
适用于所有输入流
char *fgets( char *string, int n, FILE *stream );
函数返回值 返回string,读到文件结尾返回NULL 函数参数: string:存储字符串的地址 n:读入字符的最大数目,实际读入的是n-1个字符+’\0’ stream:读入数据的文件指针
fputs
int fputs( const char *string, FILE *stream );
函数返回值: 如果输入成功返回一个非零的数,如果输入失败返回EOF 函数参数: string:要输入的字符串的地址 stream:文件的指针
格式化输入、输出函数
fprintf
实用所有的输出流
int fprintf( FILE *stream, const char *format [, argument ]... );
fprintf和printf的形式十分类似,只要在printf里面加一个文件指针即可
struct s
{
int i;
char b;
char d[20];
};
int main()
{
struct s a = { 10,'c',"kksk" };
FILE* pf;
pf = fopen("D:\\学习资料\\比特教育\\源代码\\Project1\\Project1\\kksk.txt", "w");
if (pf != NULL)
{
printf("打开文件成功\n");
int ret = 0;
fprintf(pf, "%d,%c,%s", a.i, a.b, a.d);
fclose(pf);
}
return 0;
}
fprintf的最大优点可以一次性输入类型不同的数据
fscanf
适用于所有输入流
int fscanf( FILE *stream, const char *format [, argument ]... );
fscanf和scanf十分相像
struct s
{
int i;
char b;
char d[20];
};
int main()
{
struct s a = { 0};
FILE* pf;
pf = fopen("D:\\学习资料\\比特教育\\源代码\\Project1\\Project1\\kksk.txt", "r");
if (pf != NULL)
{
printf("打开文件成功\n");
int ret = 0;
fscanf(pf,"%d %c %s", &(a.i), &(a.b), a.d);
printf("%d %c %s", a.i, a.b, a.d);
fclose(pf);
}
return 0;
}
二进制输入、输出
前面所有的所有函数都是以文本的形式输入文件
fwrite
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
函数返回值: 返回的是实际写入的元素的个数,如果写入的元素个数小于count返回就会出现错误 函数参数: buffer:指向要写的数据的指针 size:要写的元素的大小 count:要写的size大小的元素的个数 stream:要写到的文件指针
struct s
{
int i;
char b;
char d[20];
};
int main()
{
struct s a = { 10,'c',"sfdfqwdqd"};
struct s c = { 0 };
FILE* pf;
pf = fopen("D:\\学习资料\\比特教育\\源代码\\Project1\\Project1\\kksk.txt", "w");
if (pf != NULL)
{
printf("打开文件成功\n");
fwrite(&a, sizeof(struct s), 1, pf);
fclose(pf);
}
return 0;
}
结构体a的数据以二进制的形式存入了文件
fread
函数返回值: 返回的是实际读取的元素的个数,如果写入的元素个数小于count返回就会出现错误并停止读取 函数参数: buffer:指向要写的数据的指针 size:要写的元素的大小 count:要写的size大小的元素的个数 stream:要写到的文件指针
struct s
{
int i;
char b;
char d[20];
};
int main()
{
struct s a = { 10,'c',"sfdfqwdqd"};
struct s c = { 0 };
FILE* pf;
pf = fopen("D:\\学习资料\\比特教育\\源代码\\Project1\\Project1\\kksk.txt", "r");
if (pf != NULL)
{
printf("打开文件成功\n");
fread(&c, sizeof(struct s), 1, pf);
printf("%d %c %s", c.i, c.b, c.d);
fclose(pf);
}
return 0;
}
scanf | 针对标准输入的格式化输入语句 |
---|
pritnf | 针对标准输出的格式化输入语句 | fscanf | 针对所有输入的格式化输入语句 | fprintf | 针对所有输出的格式化输入语句 | sscanf | 把一个字符串转换成格式化数据 | spritnf | 把一个格式化数据转换成字符串 |
补充
scanf和sprintf
完成格式化数据->字符串->格式化数据的转换
struct S
{
int a;
char b;
char c[20];
};
int main()
{
struct S m = { 10,'c',"ssssssssssss" };
struct S n = { 0 };
char buffer[100];
sprintf(buffer, "%d %c %s", m.a, m.b, m.c);
printf("%s\n",buffer);
sscanf(buffer, "%d %c %s", &(n.a), &(n.b), n.c);
printf("%d %c %s", n.a, n.b, n.c);
}
文件的随机读写
fseek
根据文件指针的位置和偏移量来定位文件指针
int fseek( FILE *stream, long offset, int origin );
函数参数: offset:偏移量 origin:起始位置分为如下指令:
- SEEK_CUR:当前指针 的位置
- SEEK_END:从文件的结尾开始
- SEEK_SET:从文件的起始位置开始偏移
ftell
返回文件指针相对于起始位置的偏移量
long ftell( FILE *stream );
rewind
让文件指针的位置回到文件的起始位置
void rewind( FILE *stream );
文件结束判断
被错误使用的feof 牢记:在文件读取过程中,不能用eof的返回值判断文件是否读取结束。 eof适用于判断当文件读取结束的原因:读取失败结束 或 遇到文件结尾结束
判断文件读取结束的方法:利用函数的返回值
-
文本文件读取是否结束,判断返回值是否为EOF,或者空指针 - fetc函数读取结束时,会返回EOF。其他正常读取时返回读取的字符的阿斯克码值
- fgets函数读取结束时,会返回NULL。其他正常读取时返回读取的字符串的起始地址
在这里插入代码片
- 二进制文件读取结束判断,判断返回值是否小于实际要读的个数
fread函数读取的时候返回的是实际读取的完整元素的个数,如果发现读取到的完整元素个数小于指定元素个数,就是最后一次读取
|