一: 为什么使用文件
二: 什么是文件
2.1 文件
2.2 文件名
三:文件的打开和关闭
3.1 文件指针
FILE* pf;//文件指针变量
3.2 文件的打开和关闭
//打开文件 第一个参数为文件名 第二个参数为打开方式
FILE* pf=fopen(const char* filename,const char* mode);
//关闭文件
FILE* pf=fclose(FILE* stream);
打开方式如下:
文件使用方式
|
含义
|
如果指定文件不存在
|
“r”
(只读)
|
为了输入数据,打开一个已经存在的文本文件
|
出错
|
“w”
(只写)
|
为了输出数据,打开一个文本文件
|
建立一个新的文件
|
“a”
(追加)
|
向文本文件尾添加数据
|
建立一个新的文件
|
“rb”
(只读)
|
为了输入数据,打开一个二进制文件
|
出错
|
"wb”
(只写)
|
为了输出数据,打开一个二进制文件
|
建立一个新的文件
|
“ab”
(追加)
|
向一个二进制文件尾添加数据
|
出错
|
"r+”
(读写)
|
为了读和写,打开一个文本文件
|
出错
|
"w+”(读写) |
为了读和写,建议一个新的文件
|
建立一个新的文件
|
“a+”
(读写)
|
打开一个文件,在文件尾进行读写
|
建立一个新的文件
|
“rb+”
(读写)
|
为了读和写打开一个二进制文件
|
出错
|
“wb+”
(读写)
|
为了读和写,新建一个新的二进制文件
|
建立一个新的文件
|
“ab+”
(读写)
|
打开一个二进制文件,在文件尾进行读和写
|
建立一个新的文件
|
实例:
/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开文件
pFile = fopen ("myfile.txt","w");
//文件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭文件
fclose (pFile);
pFile=NULL;
}
return 0;
}
四:文件的顺序读写
4.1 文件的读写概念
顺序读写就是从文件的开头按顺序进行读写操作
首先我们要明白读和写的概念是什么:
4.2 流的介绍
流 是一个高度抽象的概念,我们可以把它理解为信息流,数据流
比如说程序员想把数据放到屏幕上,文件里,硬盘上等等,需要打开对应设备的流,把信息放在流里, 流再把数据放到相应位置.
我们向文件里写信息,需要先打开文件,返回了一个FILE*的指针,这个指针就是指向的流,这样我们就可以向文件里输入信息了
这时,有同学就会问,好像我们用printf scanf时也没有打开什么东西,直接用就可以在屏幕上输入输出信息那是怎么回事?
那是因为c语言程序只要运行起来就默认打开了三个流:
- 标准输入流:stdin
- 标准输出流:stdout
- 标准错误流:stderr
当我们用scanf从键盘读数据时就是从标准输入流里读数据
当我们用printf从屏幕打印数据时就是从标准输出流里输出数据
例如: 我们不用printf向屏幕输出数据
下面是文件常用的读写函数:
功能
|
函数名
|
适用于
|
字符
输入函数
|
fgetc
|
所有输入流
|
字符
输出函数
|
fputc
|
所有输出流
|
文本
行输入函数
|
fgets
|
所有输入流
|
文本
行输出函数
|
fputs
|
所有输出流
|
格式化
输入函数
|
fscanf
|
所有输入流
|
格式化
输出函数
|
fprintf
|
所有输出流
|
二进制输入
|
fread
|
文件
|
二进制输出
|
fwrite
|
文件
|
4.3 函数介绍
字符输入函数 fgetc()
int fgetc ( FILE * stream );
从文件流中读取一个字符,读取正常的话,返回所读字符的ASCLL值,若读取到文件末尾,读取失败,则返回EOF
使用实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1; //异常返回
}
int ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c", ch);
fclose(pf);
pf = NULL;
return 0;
}
字符输出函数fputc()
int fputc ( int character, FILE * stream );
将character写到文件流中,写入成功返回character的ASCLL,失败则返回EOF
使用实例: 把二十六个字母写到文件中
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1; //异常返回
}
for (char i = 'a'; i <= 'z'; i++)
{
fputc(i, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
文本行输入函数fgets():
char * fgets ( char * str, int num, FILE * stream );
从流中读取num-1个字符放到str所指空间中,并返回str首地址,如果读取过程中遇到\n就停止读取
例如:
假设data.txt中内容如下
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1; //异常返回
}
int arr[20] = { 0 };
fgets(arr, 10, pf);
printf("%s\n", arr);
fclose(pf);
pf = NULL;
return 0;
}
答案可见虽然我们想提取文件中的9个字符,但是遇到\n时提取就结束了
格式化输出函数fprintf():
int fprintf ( FILE * stream, const char * format, ... );
把格式化数据写到流中
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct S
{
float f;
char c;
int n;
};
int main()
{
struct S s = { 3.14f, 'w', 100 };
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fprintf(pf, "%f-%c-%d", s.f, s.c, s.n);
fclose(pf);
pf = NULL;
return 0;
}
格式化输入fscanf():
int fscanf ( FILE * stream, const char * format, ... );
把带格式的数据从流中读出来
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct S
{
float f;
char c;
int n;
};
int main()
{
struct S s = {0};
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fscanf(pf, "%f-%c-%d", &(s.f), &(s.c), &(s.n));
printf("%f-%c-%d\n", s.f, s.c, s.n);
fclose(pf);
pf = NULL;
return 0;
}
补充知识点:
ssprintf(): 将格式化数据放到字符串中
int sprintf ( char * str, const char * format, ... );
sscanf():将带有格式的字符串提取成格式化数据
#include<stdio.h>
struct S
{
float f;
char c;
int n;
};
int main()
{
struct S s = { 3.14f, 'c', 100 };
char arr[100] = { 0 };
//把格式化数据写成字符串,并将首地址传给arr
sprintf(arr, "%f-%c-%d", s.f, s.c, s.n);
printf("%s\n", arr);
struct S tmp = { 0 };
//把arr中的字符串提取成格式化数据
sscanf(arr, "%f-%c-%d", &(tmp.f), &(tmp.c), &(tmp.n));
printf("%f\n", tmp.f);
printf("%c\n", tmp.c);
printf("%d\n", tmp.n);
return 0;
}
二进制输出函数fwrite():
从ptr所指空间中提取count个大小为size的数据到流中
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
ptr:目标空间
size:每个元素的大小
count:要写入数据的个数
#include<stdio.h>
//二进制的方式写进文件
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//写文件
FILE*pf = fopen("data.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//二进制的写文件
fwrite(arr, sizeof(arr[0]), sizeof(arr)/sizeof(arr[0]), pf);
fclose(pf);
pf = NULL;
return 0;
}
可见数据被成功写入文件中,并且是我们看不懂的二进制形式
二进制输入函数fread():
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
从流中读取count个大小为size的数据到ptr所指空间
刚刚我们以二进制形式将数据写到文件中,我们同样可以以二进制形式读取出来
#include<stdio.h>
//二进制的方式读取文件
int main()
{
int arr[10] = {0};
FILE* pf = fopen("data.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//二进制的读文件
fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
fclose(pf);
pf = NULL;
return 0;
}
五:文件的随机读写
fseek()
int fseek ( FILE * stream, long int offset, int origin );
- SEEK_SET 文件开头
- SEEK_CUR 文件指针当前位置
- SEEK_END 文件末尾
ps: offest负数表示向前移,整数表示向后移
ftell()
long int ftell ( FILE * stream );
返回文件指针相对于起始位置的偏移量
rewind()
void rewind ( FILE * stream );
让文件指针的位置回到文件的起始位置
六:文件读取结束的判定
- fgetc 判断是否为EOF
- fgets 判断返回值是否为NULL
- fread 判断返回值是否小于实际要读的个数
ps:feof()是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0
在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束,而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束