C语言 — 文件
目录
- 1.流
- 1.1 流的概念
- 1.2 常见的的流
- 2.文件的打开和关闭
- 2.1 fopen函数
- 2.2 fclose函数
- 2.3 文件的打开和关闭
- 3.文件的输入输出函数
- 3.1 fputc函数
- 3.2 fgetc函数
- 3.3 feof函数和ferror函数
- 3.4 fputs函数
- 3.5 fgets函数
- 3.6 fwrite函数
- 3.7 fread函数
- 3.8 fprintf函数
- 3.9 fscanf函数
- 4 sprintf和sprintf函数
- 5. fseek函数
- 6. ftell函数和rewind函数
- 7.fflush函数
1.流
1.1 流的概念
外部设备需要从内存中写入数据进行输出,而内存需要从外部设备读取数据进行输入,为了方便外部设备与内存数据的输入输出,需要借助流帮助数据的写入与读取。
常见的外部设备有:屏幕,文件,硬盘,画面等。
1.2 常见的的流
stdin:标准输入流,从外部设备上读取数据,scanf函数就是从标准输入流(键盘)获取数据的;
stdout:标准输出流,从内存获取数据,将数据输出或写入在外部设备上,printf函数就是标准的输出流函数;
stderr:标准错误流,将错误信息输出到屏幕上;
对于文件而言,以上三种流的类型是FILE*,即文件流。
2.文件的打开和关闭
2.1 fopen函数
fopen函数的功能是将一个文件打开,并返回该文件的起始地址,类型是FILE*,第一个参数是文件路劲,第二个参数是以什么方式打开文件;
常见的文件打开方式如下
2.2 fclose函数
fclose函数的作用是打开的文件进行关闭操作,参数是需要关闭参数的起始地址,如果文件成功关闭返回0,如果关闭失败,返回EOF(-1)。
使用fclose函数成功关闭文件时,需要即时将指针置空指针,防止野指针的使用,导致程序奔溃。
2.3 文件的打开和关闭
#include<stdio.h>//文件
int main()
{//打开text.txt的文件,以写入的方式FILE* pf = fopen("test.txt", "w");//判断方式打开成功if (pf == NULL){//输出错误从原因perror("fopen");//终止程序return 1;}//使用//......//......//关闭文件,置空指针fclose(pf);pf = NULL;return 0;
}
当程序运行成功后,没有创建文件会默认创建以test.txt为路劲的文件。
3.文件的输入输出函数
3.1 fputc函数
fputc函数的功能是将指定字符通过文件输出流写入到指定的文件中,第一个参数是字符的ASCII码值,第二个参数文件的起始位置的指针。
如果返回成功写入,返回这个写入字符的ASCII码值,如果失败,就返回EOF(-1),并在输出流上设置错误信息,可以使用ferror函数输出错误信息。
fputc的使用
#include<stdio.h>//文件
int main()
{//打开text.txt的文件,以写入的方式FILE* pf = fopen("test.txt", "w");//判断方式打开成功if (pf == NULL){//输出错误从原因perror("fopen");//终止程序return 1;}//fputc使用//将a - z的字符输出写入到test.txt文件中int i = 0;for (i = 'a'; i <= 'z'; i++){putc(i, pf);}//关闭文件,置空指针fclose(pf);pf = NULL;return 0;
}
打开此时的test.txt文件:可以观察到a - z字符的内容已经输出写入到此文件中。
3.2 fgetc函数
fgetc函数的功能是从文件输入流中读取数据到内存中,参数为读取文件的起始地址。
如果读取成功,返回读取字符的ASCII码值,如果没有读取到有效内容,返回EOF(-1);分为两种情况:第一种是遇到文件末尾,在文件末尾设置指示器,可以通过feof函数检测;第二种情况是读取中途读取失败,会在读取失败的位置设置指示器,可以通过ferror函数检测。
fgetc函数的使用:读取上面的test.txt文件
#include<stdio.h>//文件
int main()
{//打开text.txt的文件,以读取的方式FILE* pf = fopen("test.txt", "r");//判断方式打开成功if (pf == NULL){//输出错误从原因perror("fopen");//终止程序return 1;}//fgetc使用//将test.txt文件中的a - z 字符读取int i = 0;for (i = 'a'; i <= 'z'; i++){printf("%c ",getc(pf));}//关闭文件,置空指针fclose(pf);pf = NULL;return 0;
}
3.3 feof函数和ferror函数
ferror函数是检测是否文件在读取或者写入的过程有失败的情况,可以通过指示器检测,如果检测到指示器,就返回非0值,如果没有检测到返回0值;
feof函数的功能是检测文件是否读取到末尾;通过指示器可以检测,如果检测到指示器,返回非0值,没有检测到指示器返回0;
feof和feeor的使用
int main()
{//打开text.txt的文件,以读取的方式FILE* pf = fopen("test.txt", "r");//判断方式打开成功if (pf == NULL){//输出错误从原因perror("fopen");//终止程序return 1;}//以读的形式打开需要输入函数读取//使用输出函数会导致读取失败//使用ferror函数和feof函数观察int r = fputc('a', pf);if (r == EOF)//读取失败的返回值{//1.判断是否读取到文件末尾if (feof(pf) != 0){printf("读取到文件末尾,返回EOF\n");}//2.判断是否在文件中途读取失败else if (ferror(pf) != 0){printf("文件在中途读取失败,返回EOF\n");}}//关闭文件,置空指针fclose(pf);pf = NULL;return 0;
}
如果将test.txt的内容删除后保存(a -z 的数据删除后CTRL + S 保存),使用以上程序的输出结果如下
3.4 fputs函数
fupus函数的功能是将内存的数据通过文件输出流中写入到文件中;第一个参数是一个不可被修改的字符串的起始地址,第二个参数是文件流的起始地址,返回类型是int。
如果写入成功返回非0值,如果写入失败,设置指示器,可以同ferror函数检测,并返回EOF(-1)。
fputs函数的使用:1.将字符串写入文件;2.将字符串输出到屏幕(控制台);
#include<stdio.h>
#include<stdlib.h>int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写入//1.写入到文件fputs("Hello", pf);//2.输出到屏幕,stdout是标准输出流fputs("World", stdout);//关闭fclose(pf);pf = NULL;return 0;
}
写入到test.txt文件中的数据
输出到控制台的数据
3.5 fgets函数
fgets函数是从文件中读取数据通过文件输入流键将数据存储到内存中;第一个参数是读取字符串的起始地址,第二个参数是读取的字符个数,第三个参数是文件流的起始地址,返回类型是char*。
如果读取成功,返回读取的字符串起始地址;在读取字符时遇到文件末尾会设置文件指示器,可以通过feof函数检测,在可读取的字符数据全部读取完成前遇到这个指示器,会返回空指针(NULL);如果读取的字符发生错误,会设置错误指示器,可以通过ferror函数检测,并返回空指针(NULL)。
fgets函数的使用:1.从文件读取;2.从外部设备读取(键盘)
#include<stdio.h>
#include<stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}char ch[12] = "************";//写入//1.读取文件信息到数组中fgets(ch,6,pf);//2.从键盘读取数据,存储到数组中//stdin是标准输入流fgets(ch + 5,7, stdin);puts(ch);//输出//关闭fclose(pf);pf = NULL;return 0;
}
按F10启动调试,打开调试监视窗口,输出ch观察数组的内容:执行ch的初始化语句
此时的text.txt文件存放的是Hello,只有5个字符,需要读取6个字符的数组,fgets函数会在末尾存放一个\0。
第二条fgets函数是从键盘读取数据,输入“ World",用空格替换’\0’的位置,后续补上World,末尾再添加一个\0。
最后通过puts函数输出数组ch的内容,将pf指向的文件关闭并置为空指针。
3.6 fwrite函数
fwrite函数是从内存获取的数据通过文件输出流以二进制是形式写入到文件中;第一个参数是写入数据的起始地址,第二个参数是元素的大小,第三个参数是个数,第四个参数是文件起始地址,返回类型是size_t.
返回值是成功写入的元素个数;如果最终读取的个数与参数的个数不一样有以下两种情况:如果返回值是0,发生写入失败,会设置错误指示器,可以通过ferror函数检测;第二种情况返回非0值,会设置文件写入结束的指示器,可以通过feof函数检测。
fwrite函数的使用
//fwrite
#include<stdio.h>
#include<stdlib.h>int main()
{//二进制写入的形式打开文件FILE* pf = fopen("test.txt", "wb");if (pf == NULL){perror("fopen");return 1;}int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//使用:将arr数组的十个元素写入到文件中 fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);//关闭fclose(pf);pf = NULL;return 0;
}
程序成功运行后,使用fwrite函数会将上一次写入的数据进行删除,后进行覆盖,以二进制的形式写入
3.7 fread函数
fread函数的功能是从文件中读取数据通过文件输入流以二进制形式输入到内存中;第一个参数数据存放位置的起始地址,第二个参数是元素的大小,第三个参数是读取的个数,第四个参数是读取数据的文件起始地址,返回类型是size_t。
如果读取成功,返回值是成功读取的个数;如果读取的个数与参数不一样有以下两种情况:如果返回值是0,发生写入失败,会设置错误指示器,可以通过ferror函数检测;第二种情况返回非0值,会设置文件写入结束的指示器,可以通过feof函数检测。
fread函数的使用:以上述的text,txt文件为例。
#include<stdio.h>
#include<stdlib.h>int main()
{//二进制读取的形式打开文件FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return 1;}int arr[10] = {0};//使用:将pf的数据读取后存放于arr数组中. fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);//输出arrfor (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}//关闭fclose(pf);pf = NULL;return 0;
}
将鼠标移向源文件窗口,点击右键打开添加中的现有项,点击text.txt文件,添加到源文件中。
点击test.txt文件,点击鼠标右键选择打开方式,选择以二进制方式打开。
可以观察到执行以上程序后arr数组读取数据的内容:1 - 10(十六进制的形式,小端存储)
3.8 fprintf函数
fprinf函数是将内存的数据通过文件输出流以指定格式的数据写入到文件中;第一个参数是文件流,第二个参数是数据的格式,第三个参数是对于的变量,返回类型是int。
如果写入成功返回写入的个数;如果写入过程出现错误,设置错误信息的指示器,并返回一个负数;如果在写入宽字符时出现多个错误,会将错误码(errno)实在为EILSEQ,并返回一个负数。
fprintf函数的使用
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)struct Stu
{char name[20];int age;char id[8];
}s = { "James",21,"22334455" };int main()
{//以写入的形式打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//使用:将结构体按照指定格式写入文件中fprintf(pf, "%s %d %s", s.name, s.age, s.id);struct Stu s1;//关闭fclose(pf);pf = NULL;return 0;
}
程序运行后的text.txt的信息
3.9 fscanf函数
fscanf函数的功能是从文件中读取的数据通过文件输入流将数据输入到内存中;第一个参数是读取数据的文件起始地址,第二个参数是按照指定格式读取数据,第三个参数是将数据存储位置的地址,返回类型是int.
如果成功读取,返回成功读取的个数;如果在全部数据读取完成前发生读取错误或读取到文件末尾,返回EOF(-1),分别通过ferror函数和feof函数检测。
fscanf函数的使用:以上述的text.txt文件的数据读取.
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)struct Stu
{char name[20];int age;char id[8];
}s1 ;
int main()
{//以读取的形式打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//使用:将文件的数据按照指定格式存放于变量s1fscanf(pf, "%s%d%s", &s1.name, &s1.age, &s1.id);//按照格式输出printf("name: %s\nage: %d\nid: %s", s1.name, s1.age, s1.id);//关闭fclose(pf);pf = NULL;return 0;
}
输出从文件中按照指定格式的数据
4 sprintf和sprintf函数
sprintf函数的功能是将格式化的数据写入到字符串中;第一个参数是字符串的起始地址,第二个参数是指定格式,第三个参数是指定成员。
如果输出成功,返回成功输出的个数,如果输出失败返回一个负数。
sscanf函数的功能是从字符串中按照格式化的方式读取数据;第一个参数是字符串的起始地址,第二个参数是指定格式,第三个参数是变量的地址。
如果转换成功返回的是格式列表的项数(与scanf函数的返回值一样,例如:”%s %d“的格式读取成功返回2 ),如果读取失败返回-1.
sscanf和sprintf的使用
#include <stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)
struct Stu
{char name[30];int age;float score;
};
int main()
{struct Stu s = { "zhangsan", 100, 85.5f };//将s中的结构数据转换成⼀个字符串char arr[100] = { 0 };sprintf(arr, "%s %d %.1f", s.name, s.age, s.score);printf("%s\n", arr);//将字符串按照格式输出struct Stu s1;sscanf(arr, "%s %d %f", s1.name, &s1.age, &s1.score);printf("%s %d %.1f", s1.name, s1.age, s1.score);return 0;
}
输出内容
scanf,printf,fscanf,fprintf,sscanf,sprintf的作用如下
5. fseek函数
fseek可以设置光标位置,使文件从此光标位置开始读取;第一个参数是文件起始位置的地址,第二个参数是偏移量的大小,第三个参数是光标的起始位置,返回类型为int.
第三个参数的取值可以是以上三种,SEEK_SET(起始位置),SEEK_CUR(当前光标的位置),SEEK_END(文件末尾)。
如果成功设置光标位置,返回0,如果设置失败,返回非0值并设置错误指示器(ferror)。
fseek的使用:将text.txt的内容先输入abcdef后保存。
#include<stdio.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//fseek函数使用//开始光标位置在0偏移处,将光标设置在1偏移量位置fseek(pf, 1, SEEK_SET);//指向字符a后面的位置int c = fgetc(pf);//读取到b字符,光标移向b后面的位置printf("%c", c);//输出字符b//将光标设置在当前位置的后1偏移量位置fseek(pf, 1, SEEK_CUR);//指向b后面的位置c = fgetc(pf);//读取到字符c,光标指向c后面位置printf("%c", c);//输出c//将光标设置在文件末尾的前1偏移量位置fseek(pf, -1,SEEK_END);c = fgetc(pf);//读取到字符f,光标指向字符f后面printf("%c", c);//输出f//关闭fclose(pf);pf = NULL;return 0;
}
6. ftell函数和rewind函数
ftell函数是将当前光标的位置与起始位置的偏移量值返回,如果未能读取返回-1L(double);
rewind函数是将光标设置为起始位置,参数是文件指针,没有返回值。
/* ftell and rewind example : getting size of a file */
#include <stdio.h>int main()
{FILE* pf = fopen("test.txt", "r");//文件内容:abcdefif (pf == NULL) perror("Error opening file");else{fseek(pf, 0, SEEK_END); // non-portablelong size = ftell(pf);printf("Size of test.txt.txt: %ld bytes.\n", size);//重新设置光标位置rewind(pf);printf("%c", fgetc(pf));//关闭文件,设置空指针fclose(pf);pf = NULL;}return 0;
}
7.fflush函数
fflush是将文件缓冲区的数据进行刷新,对于文件输入流的数据,终止读取,对于文件输出流的数据进行写入,函数的参数是文件指针,返回类型是int。
成功刷新缓冲区返回0值,刷新失败返回-1,并设置错误指示器。
fflush的使用
/* fflush example */
#pragma warning(disable:4996)
#include <stdio.h>
#include<windows.h>
char mybuffer[80];
int main()
{char mybuffer[10];FILE* pf = fopen("test.txt", "r+");if (pf == NULL){perror("fopen");//输出错误信息return 1;//终止程序}fputs("abcdef", pf);printf("数据正在存储在缓冲区中....\n");Sleep(5000);//休眠5秒fflush(pf); // flushing or repositioning requiredprintf("缓冲区已经刷新,数据写入中...\n");rewind(pf);//将光标设置在起始文件指针的位置fgets(mybuffer, 10, pf);//获取信息puts(mybuffer);//输出//关闭文件,置空指针fclose(pf);pf = NULL;return 0;
}
程序运行中还未刷新缓冲区数据,文件的内容是空的。
刷新后,abcdef写入文件中。