目录
- 文件操作
- 文件的打开和关闭
- 打开文件
- 关闭文件
- 文件打开路径
- 绝对路径
- 相对路径
- 文件的顺序读写
- 顺序读写函数介绍
- fputc
- fgetc
- fputs
- fgets
- fprintf
- fscanf
- fwrite
- fread
- 对比一组函数
- sprintf
- sscanf
- 对比
- 文件的随机读写
- fseek
- ftell
- rewind
- 文件读取结束的判定
- 如何判断文件读取结束?
文件操作
文件操作中相关的函数的头文件都是stdlib.h
文件的打开和关闭
打开文件
FILE* fopen(const char* filename, const char* mode);
返回值:FILE*是返回一个文件指针
filname是文件名
mode是打开文件的方式
打开成功返回文件信息区的地址,失败返回NULL
下面是文件的打开方式
代码解释如何打开文件
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");//以读的形式打开文件if(pf == NULL)//文件打开失败{perror("fopen");//返回打开失败的原因return 1;//异常返回}
}
关闭文件
int fclose(FILE* stream);
stream是流,也就是文件指针
代码解释关闭文件
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");//以读的形式打开文件if(pf == NULL)//文件打开失败{perror("fopen");//返回打开失败的原因return 1;//异常返回}else{printf("打开成功\n");}//关闭文件fclose(pf);pf = NULL;
}
文件打开路径
绝对路径
#include <stdio.h>
#include <stdlib.h>int main()
{//绝对路径FILE* pf = fopen("C:\\Users\\48784\\Desktop\\test.txt", "r");//以读的形式打开文件if(pf == NULL)//文件打开失败{perror("fopen");//返回打开失败的原因return 1;//异常返回}//关闭文件fclose(pf);pf = NULL;
}
相对路径
#include <stdio.h>
#include <stdlib.h>int main()
{//相对路径// . --> 当前路径// .. --> 上一级路径// /这样写不用转义 \这样写需要转义//FILE* pf = fopen("./../test.txt", "w");//在当前路径的上一个路径找test.txt//FILE* pf = fopen(".\\..\\test.txt", "w");FILE* pf = fopen("./../x64/test.txt", "w");//在当前路径的上一个路径的x64文件中找test.txtif(pf == NULL)//文件打开失败{perror("fopen");//返回打开失败的原因return 1;//异常返回}//关闭文件fclose(pf);pf = NULL;
}
文件的顺序读写
顺序读写函数介绍
上面说的适用于所有输入流一般指适用于标准输入流和其他输入流(入文件输入流)
fputc
字符输出函数 fputs
int fputc(int character, FILE* stream);
character是要写的字符
stream是流,也就是文件指针
fputc函数的作用:将字符写到文件中
写字符到文件中
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "w");//以写的形式打开文件if(pf == NULL){perror("fopen");return 1;}//写字符到文件fputc('a', pf);//关闭文件fclose(pf);pf = NULL;
}
//写字符到文件fputc('a', pf);fputc('b', pf);fputc('c', pf);fputc('d', pf);fputc('e', pf);
//写字符到文件for(int i = 'a'; i <= 'z'; i++){fputc(i, pf);}
}
fgetc
字符输入函数 fgetc
int fgetc(FILE* stream,);
stream是文件指针
fgetc函数的作用:从文件中读取字符。
读取成功返回字符的ASCII码值
当读取文件结束时有两种情况
1.遇到错误而结束,并设置一个遇到错误而结束的标记,返回EOF(-1)
2.遇到文件末尾而结束,并设置一个遇到文件末尾而结束的标记,返回EOF(-1)
从文件中读取字符
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");//以读的形式打开文件if(pf == NULL){perror("fopen");return 1;}//从文件中读取字符int ch = fgetc(pf);printf("%c\n", ch);ch = fgetc(pf);printf("%c\n", ch);ch = fgetc(pf);printf("%c\n", ch);//关闭文件fclose(pf);pf = NULL;
}
//从文件中读取字符
int ch = 0;
while((ch = fgetc(pf)) != EOF)
{printf("%c ", ch);
}
fputs
文本行输出函数 fputs
int fputs(const char* str, FILE* stream);
str是要写的字符串
stream是文件指针
fputs的作用:向文件中写一个字符串
向文件中写一个字符串
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "w");//以写的形式打开文件if(pf == NULL){perror("fopen");return 1;}//向文件中写一个字符串fputs("hello world", pf);fputs("hello bit", pf);//该函数不会自动换行//关闭文件fclose(pf);pf = NULL;
}
//向文件中写一个字符串fputs("hello world\n", pf);fputs("hello bit\n", pf);//该函数不会自动换行
fgets
文本行输入函数 fgets
char* fgets(char* str, int num, FILE* stream);
str是读取到的字符串
num是读取的字符的个数
stream是要被读取的文件
从文件中读一个字符串
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");//以读的形式打开文件if(pf == NULL){perror("fopen");return 1;}//从文件中读一个字符串char arr[20];fgets(arr, 8, pf);//假设test.txt中的字符串为abcdefghijk,共11个字符,末尾还有一个\0//此时该函数会读取num-1个字符也就是7个字符放在arr中,末尾加上\0//关闭文件fclose(pf);pf = NULL;
}
//从文件中读一个字符串
fgets(arr, 20, pf);//假设test.txt中的字符串为abcdefghijk,共11个字符,末尾还有一个\0,并且换行了。
//此时该函数会读取11个字符,再加上\n\0
fprintf
格式化输出函数 fprintf
int fprintf(FILE* stream, const char * format, …);
该函数与printf不同之处就是加了一个stream参数
fprintf函数的作用:向文件中写数据
向文件中写数据
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "w");//以写的形式打开文件if(pf == NULL){perror("fopen");return 1;}//向文件中写数据char arr[20] = "hello";int num = 100;double pai = 3.14;fprintf(pf, "%s %d %.2lf", arr, num, pai);//关闭文件fclose(pf);pf = NULL;
}
#include <stdio.h>
#include <stdlib.h>struct S
{char arr[20];int num;double pai;
};int main()
{FILE* pf = fopen("test.txt", "w");//以写的形式打开文件if(pf == NULL){perror("fopen");return 1;}//向文件中写数据struct S s = {"world", 200, 3.14}fprintf(pf, "%s %d %.2lf", s.arr, s.num, s.pai);//关闭文件fclose(pf);pf = NULL;
}
fscanf
格式化输入函数 fscanf
int fsacnf(FILE* stream, const char * format, …)
该函数与scanf不同之处就是加了一个stream参数
fscanf函数的作用:从文件中读取数据
#include <stdio.h>
#include <stdlib.h>struct S
{char arr[20];int num;double pai;
};int main()
{FILE* pf = fopen("test.txt", "r");//以读的形式打开文件if(pf == NULL){perror("fopen");return 1;}//从文件中读数据struct S s = { 0 };fscanf(pf, "%s %d %lf", s.arr, &(s.num), &(s.pai));printf("%s %d %lf\n", s.arr, s.num, s.pai);//关闭文件fclose(pf);pf = NULL;
}
fscanf(stdin, "%s %d %lf", s.arr, &(s.num), &(s.pai));
//等价于
scanf("%s %d %lf", s.arr, &(s.num), &(s.pai));
stdin是标准输入流,在大多数的环境中从键盘输入
那么
fprintf(stdout, "%s %d %lf", s.arr, s.num, s.pai);
//等价于
printf("%s %d %lf\n", s.arr, s.num, s.pai);
stdout是标准输出流,大多数的环境中输出至显示器界面
fwrite
二进制输出 fwrite 只针对文件输出流
size_t fwrite(const void** ptr, size_t size, size_t count, FILE* stream);
fwrite函数的作用:写数据块到流(文件)中
ptr是要被写的数据块
size是要被写的数据块的元素的大小,也可以说是每次要写的字节大小
count是要写的元素的个数,也可以说是要写的次数
pf是要写的文件
二进制的形式写文件
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("bin.txt", "wb");//以二进制写的形式打开文件//wb就是write binary 二进制写if(pf == NULL){perror("fopen");return 1;}//二进制的形式写文件int arr[] = {1, 2, 3, 4, 5};fwrite(arr, sizeof(arr[0]), 5, pf);//关闭文件fclose(pf);pf = NULL;
}
//二进制的形式写文件int arr[] = {1, 2, 3, 4, 5};fwrite(arr, 20, 1, pf);//一次写20个字节写1次
fread
二进制输入 fread 只针对文件输入流
size_t fread(const void* ptr, size_t size, size_t count, FILE* stream);
fread函数的作用:从流(文件)中读取数据块
ptr中放的是从(文件)中读取到的数据块
size是要读取的数据的元素的大小,也可以说是每次要读的字节的大小
count是要读的元素的个数,也可以说是要读的次数
stream是要被读的文件
二进制的形式读文件
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("bin.txt", "rb");//以二进制读的形式打开文件//rb就是read binary 二进制读if(pf == NULL){perror("fopen");return 1;}//二进制的形式读文件int arr[10] = { 0 };fread(arr, sizeof(arr[0]), 5, pf);//关闭文件fclose(pf);pf = NULL;
}
//二进制的形式读文件int arr[10] = { 0 };fread(arr, 20, 1, pf);//要读20个字节,读一次
对比一组函数
scanf / fscanf / sscanf
printf / fprintf / sprintf
前面的两组我们都学过,先说说最后一组再对比
sprintf
int sprintf(char* str, const char * format, …)
sprintf函数的作用:将格式化的数据转换成字符串放在str中
#include <stdio.h>
#include <stdlib.h>struct S
{char arr[20];int num;double pai;
};int main()
{struct S s = { "world", 201, 3.14 };char arr[30] = { 0 };sprintf(arr, "%s %d %lf", s.arr, s.num, s.pai);printf("%s\n", arr);return 0;
}
sscanf
int sscanf(const char* s, const char* format, …);
将字符串转换成格式化的数据
#include <stdio.h>
#include <stdlib.h>struct S
{char arr[20];int num;double pai;
};int main()
{struct S s = { "world", 201, 3.14 };char arr[30] = { 0 };sprintf(arr, "%s %d %lf", s.arr, s.num, s.pai);printf("字符串:%s\n", arr);struct S t = { 0 };sscanf(arr, "%s %d %lf", s.arr, &(s.num), &(s.pai));printf("结构体:%s %d %lf\n", t.arr, t.num, t.pai);return 0;
}
对比
scanf/printf 针对标准输入(stdin-键盘)输出(stdout-屏幕)流的格式化的输入/输出函数
fscanf/fprintf 针对所有输入流/所有输出流的格式化的输入/输出函数
sscanf 将字符串转换成格式化的数据
sprintf 将格式化的数据转换成字符串
文件的随机读写
fseek
int fseek(FILE* stream, long int offset, int origin);
stream是流(文件)
offset是偏移量
origin是位置
fseek函数的作用:根据文件指针的位置和偏移量来定位文件指针(文件内容中的光标)
origin有三个取值
SEEK_SET 文件起始位置
SEEK_CUR 文件指针(文件内容中的光标)的当前位置
SEEK_END 文件末尾位置
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");if(pf == NULL){perror("fopen");return 1;}//假设test.txt中是abcdefint ch = fgetc(pf);fputc(ch, stdout);//'a'//定位文件指针指向'd'fseek(pf, 3, SEEK_SET);//fseek(pf, 2, SEEK_CUR);//fseek(pf, -3, SEEK_END);//这三种写法都行ch = fgetc(pf);fputc(ch, stdout);//'d'//关闭文件fclose(pf);pf = NULL;return 0;
}
ftell
long int ftell(FILE* stream);
ftell函数的作用:返回文件指针相对于起始位置的偏移量
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");if(pf == NULL){perror("fopen");return 1;}//假设test.txt中是abcdefint ch = fgetc(pf);fputc(ch, stdout);//'a'//定位文件指针指向'd'fseek(pf, 3, SEEK_SET);//fseek(pf, 2, SEEK_CUR);//fseek(pf, -3, SEEK_END);//这三种写法都行ch = fgetc(pf);fputc(ch, stdout);//'d'//此时文件光标指向'e'//计算'e'相对于起始位置的偏移量long int r = ftell(pf);printf("%ld\n", r);//4//关闭文件fclose(pf);pf = NULL;return 0;
}
rewind
void rewind(FILE* stream);
rewind函数的作用:让文件指针回到起始位置
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}int ch = fgetc(pf);fputc(ch, stdout);//'a'//定位文件指针指向'd'//fseek(pf, 3, SEEK_SET);//fseek(pf, 2, SEEK_CUR);fseek(pf, -3, SEEK_END);ch = fgetc(pf);fputc(ch, stdout);//'d'//文件指针(光标)指向'e'//计算'e'相对于起始位置的偏移量long int r = ftell(pf);printf("%ld\n", r);//4//让文件指针回到起始位置rewind(pf);ch = fgetc(pf);fputc(ch, stdout);//'a'fclose(pf);pf = NULL;return 0;
}
文件读取结束的判定
当读取文件结束时,有两种情况
1.遇到文件末尾而结束
2.遇到错误而结束
回忆fgetc
当fgetc读取结束时,有两种情况
1.遇到文件末尾而结束,并设置一个遇到文件末尾而结束的标记,返回EOF
2.遇到错误而结束,并设置一个遇到错误而结束的标记,返回EOF
函数feof的作用:当文件读取结束的时候,判断读取结束的原因是否为:遇到文件末尾而结束
函数ferror的作用:当文件读取结束的时候,判断读取结束的原因是否为:遇到错误而结束
如何判断文件读取结束?
1.对于文本文件读取是否结束,判断返回值是否为EOF,或者NULL
例如:
fgetc判断是否返回EOF
fgets判断是否返回NULL
2.对于二进制文件读取是否结束,判断返回值是否小于实际要读的个数
例如:
fread判断返回值是否小于实际要读的个数
文本文件的例子
#include <stdio.h>
#include <stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int ch = 0;while ((ch = fgetc(pf)) != EOF){fputc(ch, stdout);}//判断文件读取结束的原因if (feof(pf))printf("遇到文件末尾\n");else if (ferror(pf))printf("遇到错误\n");fclose(pf);pf = NULL;return 0;
}
二进制文件的例子
#include <stdio.h>
#include <stdlib.h>enum { SIZE = 5 };int main(void)
{double a[SIZE] = { 1.,2.,3.,4.,5. };FILE* fp = fopen("bin.txt", "wb"); //必须⽤⼆进制模式fwrite(a, sizeof * a, SIZE, fp); // 写double的数组fclose(fp);double b[SIZE];fp = fopen("bin.txt", "rb");size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读double的数组if (ret_code == SIZE) {printf("读取文件成功\n");for (int n = 0; n < SIZE; ++n)printf("%f ", b[n]);putchar('\n');}else { if (feof(fp))printf("遇到文件末尾而结束\n");else if (ferror(fp)){perror("遇到错误未结束\n");}}fclose(fp);
}