文件
创建写入读取文件
创建或打开 fopen函数
原型FILE* fopen(const char* filename, const char* mode);
前者是文件路径 相对路径(从当前目录开始定位的路径)data.txt 绝对路径(从顶级目录开始定位的路径)D:/projects/data.txt
后者是操作模式
若创建成功则返回一个指针
操作模式
- 读取
"w"写模式 会清空原有文件内容 - 写入
"r"读模式 - 追加
a追加模式 保留原内容 在文件尾部添加新内容 - 二进制
b二进制模式 wb rb - 更新
+可读可写
1.w+可读可写 但会清空文件原有内容
2.r+可读可写
输出到文件 fprintf函数
原型int fprintf(FILE * stream, const char* format, ...);
在printf之前加了个文件结构指针参数 后面参数同printf函数 用w模式
读取文件 fscanf函数
原型int fscanf(FILE * stream, const char* format, ...);
在scanf之前加了个文件结构指针参数 后面参数同scanf函数 用r模式
关闭文件 fclose函数
原型fclose(FILE * stream);
示例
#include<stdio.h>
int main()
{
//创建名为data.txt的文件
FILE* pFile = fopen("D:/data.txt", "w");
if (pFile == NULL)
{
return -1;//若创建失败
}
//若创建成功
int n = 123;
double f = 123.456;
char ch = 'A';
fprintf(pFile, "%d\n", n);//第一个参数为文件结构指针
fprintf(pFile, "%lf\n", f);
fprintf(pFile, "%c\n", ch);
fclose(pFile);//关闭文件
return 0;
}
#include<stdio.h>
int main()
{
//打开名为data.txt的文件
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
{
return -1;//若打开失败
}
//若打开成功
int n;
double f;
char ch;
fscanf(pFile, "%d", &n);//第一个参数为文件结构指针
fscanf(pFile, "%lf", &f);
fscanf(pFile, "%c", &ch);//fscanf读取了字符\n赋值给了ch
printf("%d\n", n);
printf("%lf\n", f);
printf("%c\n", ch);
fclose(pFile);//关闭文件
return 0;
}
读取单个字符 fgetc函数
原型int fgetc(FILE * stream);
类似getchar()
若读取成功 返回读取到的字符 若读取失败 返回EOF
#include<stdio.h>
int main()
{
//打开名为data.txt的文件
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
{
return -1;//若打开失败
}
//若打开成功
char ch;
while (1)
{
ch = fgetc(pFile);
if (ch == EOF)
break;//文件结尾或者其他错误
putchar(ch);
}
fclose(pFile);//关闭文件
return 0;
}
读取字符串 fgets函数
原型char* fgets(char* str, int num, FILE * stream);
将读取的字符串储存在以str为首的首地址中
num 读取的最大字符数
stream 文件结构指针
#include<stdio.h>
int main()
{
//打开名为data.txt的文件
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
{
return -1;//若打开失败
}
//若打开成功
char str[100];
while (fgets(str, 100, pFile))
printf("%s", str);
fclose(pFile);
return 0;
}
文件状态判断
- feof测试文件是否结尾
- ferror测试文件是否读写出错
int feof(FILE * stream);若文件结尾返回值为非0 否则返回值为0
int ferror(FILE * stream);若文件读写出错返回值为非0 否则返回值为0
#include<stdio.h>
int main()
{
//打开名为data.txt的文件
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
{
return -1;//若打开失败
}
//若打开成功
char ch;
while (1)
{
ch = fgetc(pFile);
if (ch == EOF)
{
if (feof(pFile) != 0)
printf("end of file\n");
if (ferror(pFile) != 0)
printf("file access error\n");
break;
}
putchar(ch);
}
fclose(pFile);
return 0;
}
写入单个字符 fputc函数
原型int fputc(int character, FILE * stream);
输入写入的字符和文件结构指针
写入成功返回刚刚写入的字符 文件结尾或失败返回EOF
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "w");//写模式
if (pFile == NULL)
{
return -1;
}
char str[] = "HelloWorld\n";
char* p = str;
while (*p != '\0')
{
//向文件中写入一个字符
fputc(*p, pFile);
p++;
}
fclose(pFile);
return 0;
}
写入一串字符串 fputs函数
原型fputs(const char* str, FILE * stream);
输入写入的字符串和文件结构指针
写入成功返回非负值 写入失败返回EOF
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "w");//写模式
if (pFile == NULL)
{
return -1;
}
char str[] = "HelloWorld\n";
for (int i = 0; i < 5; i++)
{
//写入五行
fputs(str, pFile);
}
fclose(pFile);
return 0;
}
刷新缓存 fflush函数
原型fflush(FILE * stream);
文件操作函数数据会先写到缓存里 然后一起写入文件 清空缓存区数据 称为刷新缓存 即使没有运行到fclose或关闭程序 也可以保存到文件中
成功刷新返回0 否则返回EOF
文件偏移
文件指针移动 fseek函数
原型int fseek(FILE * stream,long offset, int origin);
输入 文件结构指针 文件指针偏移量 从什么位置开始偏移
如果成功 返回0 否则返回一个非零值
fseek(pFile, 5,SEEK_SET);从文件开头偏移5个字节
fseek(pFile, 0,SEEK_SET);文件指针回到文件最开始
fseek(pFile,-5,SEEK_END);从文件结尾偏移-5个字节
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "r");//读模式
if (pFile == NULL)
{
return -1;
}
char ch;
//从文件开头偏移5个字节
fseek(pFile, 5,SEEK_SET);
ch = fgetc(pFile);
putchar(ch);
//从文件结尾偏移-5个字节
fseek(pFile, -5,SEEK_END);
ch = fgetc(pFile);
putchar(ch);
fclose(pFile);
return 0;
}
获取当前文件指针位置 ftell函数
原型long ftell (FILE * stream);
输入文件结构指针
成功返回当前指针位置 失败返回-1
如果将文件指针先偏移到末尾 再获取文件指针当前的位置 就能知道该文件内有多少个字节 即该文件的大小
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "r");//读模式
if (pFile == NULL)
{
return -1;
}
char ch;
//偏移到文件结尾
fseek(pFile, 0,SEEK_END);
//获取当前文件指针位置
long length = ftell(pFile);
printf("size of file %ld\n", length);
fclose(pFile);
return 0;
}
指针归零 rewind函数
void rewind (FILE * stream);
输入指针 无输出
文件指针回到文件最开始
更新文件
- 文件从写操作转换为读操作前 必须使用fflush fseek rewind其中一个函数
- 文件从读操作转换为写操作前 必须使用fseek rewind其中一个函数
- 在代码中读写操作转换的地方加入必要函数 如果仅需要读写操作转换 但无需变动文件指针 可以在当前位置偏移0字节
fseek(pFile,0,SEEK_CUR);
eg 把Helloworld的H改成h
代码中使用fgetc 读取文件中的每个字符 若读到字符H 则把这个字符使用fputc修改为h 注意fgetc读取到字符H后 文件指针已经指向了下一个字符 所以 若读取到字符H 需要将文件指针向前移动一个字节 再进行修改
#include<stdio.h>
void fileEofOrError(FILE* pFile)
{
if (feof(pFile) != 0)//测试文件是否结尾
printf("end of file\n");
else if (ferror(pFile) != 0)//测试文件是否读写出错
printf("file access error\n");
}
int main()
{
FILE* pFile = fopen("D:/data.txt", "r+");
if (pFile == NULL)
{
return -1;
}
char ch;
while (1)
{
ch = fgetc(pFile);
if (ch == EOF)
{
fileEofOrError(pFile);
break;
}
if (ch == 'H')//文件指针向前移动一个字节
{
//读转写
fseek(pFile, -1, SEEK_CUR);
ch = fputc('h', pFile);
if (ch == EOF)
{
fileEofOrError(pFile);
break;
}
//写转读
fflush(pFile);
}
}
fclose(pFile);
return 0;
}
数值与字符串
将数值转化成字符串保存
数值位数越多 占用空间越大
int numbers[8] = { 1,12,123,1234,12345,10,123456,1234567 };转换成字符串保存到文件中
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "w");
if (pFile == NULL)
return -1;
int numbers[8] = { 1,12,123,1234,12345,10,123456,1234567 };
for (int i = 0; i < 8; i++)
fprintf(pFile, "%d\n", numbers[i]);
fclose(pFile);
return 0;
}
读取字符串转成数值
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
return -1;
int numbers[8] = { 0 };
for (int i = 0; i < 8; i++)
fscanf(pFile, "%d" , & numbers[i]);
for (int i = 0; i < 8; i++)
printf("%d\n", numbers[i]);
fclose(pFile);
return 0;
}
除了使用固定长度的循环 还可以通过函数fscanf 的返回值判断是否已经读完文件
函数fscanf的返回值的意义为 参数列表中成功填充的参数个数 若文件读取失败或文件结尾则返回EOF
若返回EOF 可以通过feof以及ferror函数查询具体的原因 我们可以使用之前定义的函数fileEofOrError 来判断究竟是哪种情况
#include<stdio.h>
void fileEofOrError(FILE* pFile)
{
if (feof(pFile) != 0)//测试文件是否结尾
printf("end of file\n");
else if (ferror(pFile) != 0)//测试文件是否读写出错
printf("file access error\n");
}
int main()
{
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
return -1;
int numbers[8] = { 0 };
int count = 0;
while (1)
{
if (count >= 8)//为防止越界 若已经填满8个元素 则不继续读取
{
printf("numbers is full\n");
break;
}
//fscanf从文件中获取字符串并转换为数值
int get = fscanf(pFile, "%d", &numbers[count]);
printf("%d,", get);//成功填充了几个参数
if (get == EOF)
{
fileEofOrError(pFile);
break;
}
count++;
}
putchar('\n');
for (int i = 0; i < 8; i++)
printf("%d\n", numbers[i]);
fclose(pFile);
return 0;
}
数值与二进制
除了可以把数值转为字符串保存 还能把数值直接以二进制形式保存成文件
二进制输出 fwrite函数
原型size_t fwrite(const void *buffer, size_t size,size_t count,FILE*stream);
输入 待写入文件数据的首地址 每一块数据的大小 一共有多少块数据 文件结构指针
返回值 成功写入多少块数据 失败返回0
#include<stdio.h>
void fileEofOrError(FILE* pFile)
{
if (feof(pFile) != 0)//测试文件是否结尾
printf("end of file\n");
else if (ferror(pFile) != 0)//测试文件是否读写出错
printf("file access error\n");
}
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "w");
if (pFile == NULL)
return -1;
//装有数值的数组
int numbers[8] = { 1,12,123,1234,12345,10,123456,1234567 };
//numbers转化为首元素指针 同时丢失指针类型信息
//将数组numbers分为1块 每一块sizeof(numbers)大小
fwrite(numbers, sizeof(numbers), 1, pFile);
//或者将数组numbers分成8块 每一块sizeof(int)大小
fwrite(numbers, sizeof(int), 8, pFile);
fclose(pFile);
return 0;
}
二进制读取 fread函数
原型size_t fread(void *buffer,size_t size, size_t count,FILE *stream );
输入 收数据的首地址 每一块数据的大小 一共有多少块数据 文件结构指针
返回值成功读取多少块数据 失败返回0
#include<stdio.h>
void fileEofOrError(FILE* pFile)
{
if (feof(pFile) != 0)//测试文件是否结尾
printf("end of file\n");
else if (ferror(pFile) != 0)//测试文件是否读写出错
printf("file access error\n");
}
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
return -1;
//接受数据的数组
int numbers[8] = { 0 };
//每块读取sizeof(numbers)字节 一共读取1块
fread(numbers, sizeof(numbers), 1,pFile);
for(int i=0;i<8;i++)
printf("%d\n", numbers[i]);
fclose(pFile);
return 0;
}
除了读取固定大小的数据 我们也能让fread每次读取一字节数据 直到文件结尾或接收的空间存满为止
#include<stdio.h>
void fileEofOrError(FILE* pFile)
{
if (feof(pFile) != 0)//测试文件是否结尾
printf("end of file\n");
else if (ferror(pFile) != 0)//测试文件是否读写出错
printf("file access error\n");
}
#include<stdio.h>
int main()
{
FILE* pFile = fopen("D:/data.txt", "r");
if (pFile == NULL)
return -1;
int numbers[8] = { 0 };//接受数据的数组
char* p = (char*)(numbers);//接受数据的首地址
int count = 0;//已读取的字节
while (1)
{
//如果数组已经读满8个元素 则不继续读取
if (count >= sizeof(numbers))
{
printf("numbers is full\n");
break;
}
//每块读取1字节 一共读取1块
int get = fread(p, 1, 1, pFile);//fread函数将读取到的1字节数据 存放到指针p中保存的地址当中
if (get == EOF)
{
fileEofOrError(pFile);
break;
}
p++;//将接收数据的地址向后移动一字节
count++;
}
for(int i=0;i<8;i++)
printf("%d\n", numbers[i]);
fclose(pFile);
return 0;
}