文件指针
文件指针变量
FILE* p;
定义一个指向FILE类型的指针变量,可以通过这个指针变量找到与之相关的文件。
文件的打开和关闭
与动态内存类似,文件使用前需要fopen函数打开,试用结束后用fclose函数关闭。
fopen的第一个参数是文件名,第二个参数是文件打开方式,返回一个文件指针。
打开文件有两种方式,一种是文件相对路径,一种是文件绝对路径。
默认当前路径。
FILE* pf = fopen("test.txt", "w");
FILE* pf = fopen(".\\test.txt", "w");//表示这个文件在当前路径下 相对路径
FILE* pf = fopen("C:\\Users\\86198\\Desktop\\cc文件\\test.txt", "w");// 绝对路径
FILE* pf = fopen("..\\test.txt", "w");//这样可以找到上一层路径下的test文件 相对路径
文件的建立或打开可能会出错导致文件指针接收不到一个值从而出现野指针,所以需要在文件指针接收后用一个if语句判断文件指针是否成功接收,避免出现野指针的解引用操作。
fclose通过文件指针关闭文件,如果成功关闭则会返回一个0,如果失败则会返回EOF。
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fclose(pf);
pf = NULL;
return 0;
}
注意在关闭后将文件指针置空否则会出现野指针。
当代码运行到13行时,文件已经被关闭了,但是指针pf依旧有值,无法通过这个地址查询到test文件,则pf就会变成野指针。
文件的顺序读写
所有输出流包括文件流和标准输出流等。
字符输出函数
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//fputc('a', pf);
//fputc('b', pf);
//fputc('c', pf);
//fputc('d', pf);将字符存到文件中
fputc('a', stdout);
fputc('b', stdout);
fputc('c', stdout);
fputc('d', stdout);
//将字符通过标准输出流打印到屏幕
fclose(pf);
pf = NULL;
return 0;
}
字符输入函数
当读取成功时会返回一个ASCII值,读取失败时会返回一个EOF并设置一个错误提示。
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr = fgetc(pf);
printf("%c", arr);
fclose(pf);
pf = NULL;
return 0;
}
文本行输出函数
与fputc类似,fputs是将字符串传给流。
文本行输入函数
fgets是从流中获取一个字符串,第一个参数是目标字符串地址,第二个参数是最多接收num-1个字符,第三个参数是流,返回一个字符地址。
当读到换行或者到了num-1个时就会截至。
格式化输出函数
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;
}
格式化输入函数
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;
}
二进制输出函数
写一个数据块到流中,把来自ptr的数组中count个数据,每个数据大小为size,写入到stream流中。
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;
}
二进制输入函数
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;
}
扩展两个函数
sprintf
将格式化的数据转换为字符串
sscanf
将字符串转为格式化数据
struct S
{
float f;
char c;
int n;
};
int main()
{
struct S s = { 3.14f, 'c', 100 };
char arr[100] = { 0 };
sprintf(arr, "%f-%c-%d", s.f, s.c, s.n);
printf("%s\n", arr);
struct S tmp = { 0 };
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;
}
scanf是格式化的输入函数,针对是标准输入流(键盘)
printf是格式化的输出函数,针对的是标准输出流(屏幕)
fscanf是针对所有输入流(文件流、标准输入流)的格式化输入函数
fprintf是针对所有输出流(文件流、标准输出流)的格式化输出函数
sscanf是将字符串转换为格式化数据
sprintf是将格式化数据转换为字符串
文件的随机读写
fseek
根据文件指针的位置和偏移量来定位文件指针
函数第一个参数是文件指针,第二个是偏移量可正可负,第三个参数有三个值,第一个SEEK_SET表示文件起始位置,SEEK_CUR表示文件指针当前位置,SEEK_END表示文件末尾位置。
ftell
返回文件指针相对起始位置的偏移量
rewind
让文件指针返回到文件起始位置
文件读取结束的判定
feof
不能用feof的返回值直接判断文件是否结束,而是用于文件读取结束时,判断是读取失败结束,还是遇到文件尾结束。
文本文件读取是否结束,判断返回值是否为EOF(fgetc),或者NULL(fgets)。
二进制文件读取是否结束,判断返回值是否小于实际读取的个数(fread)。
ferror,在文件读取结束后,用来判断文件是否因为读取过程中遇到错误而结束,如果是因为遇到错误结束,会返回一个非0的数。
feof,在文件读取结束后,用来判断文件是否因为读取过程中遇到文件结束标志而结束,如果是文件结束也会返回一个非0的数。