文件的操作
1.为什么使用文件
我们在vs里面运行一个程序时,输入的数据是存放在内存中的。当我们下次运行程序时,之前录入的数据自然就不存在了。比如说我们写了一个通讯录的程序,我们第一次运行时在里面存入了一部分人的信息,下次运行时那些数据便会消失。使用这样的通讯录是非常不合理且难受的。
这时我们就有一个需求,希望上次录入的数据能够保存下来。而这个能够帮助我们的东西就是文件。文件的数据是储存在硬盘上的,不会随着程序的运行结束而消失。
2. 什么是文件
磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。
程序文件
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe。
储存我们写的代码的文件。
数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
我们之前在vs上的输入scanf,输出printf都是以终端为对象。即从终端的键盘输入数据,运行结果显示到显示器上。但有的时候需要我们把数据储存在磁盘上,或者有时我们要把文件的内容读取到内存中来使用。这个文件就是数据文件。
我们接下来主要介绍数据文件。
文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含三部分:文件路径,文件名主干,文件后缀
例:
为了方便起见,文件标识常被称为文件名。
3.文件的打开和关闭
文件指针
在打开一个文件的过程中在内存中编译器会自动给出一块空间来储存文件的基本信息,这些信息储存在一个结构体变量中。
该结构体类型是由系统声明的,取名为FILE
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
FILE* pf;//文件指针变量
打开的过程图解:
文件的打开和关闭
文件的打开
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
//打开文件
FILE * fopen ( const char * filename, const char * mode );
"文件名" "文件的使用方式"
//关闭文件
int fclose ( FILE * stream );
指向文件的指针
例:
int main()
{
FILE* pf = fopen("test.exe", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fclose(pf);
pf == NULL;
return 0;
}
注意点:
1.fopen和fclose必须同时出现。
2.由于存在文件无法打开的情况,所以要检验。(这里我们要了解fopen函数,它在打开失败时会返回NULL指针)。
3.fclose后文件指针会变成野指针,所以我们要将他赋为空指针。
文件的使用方式
解释一下文件不存在情况中的建立一个新文件 。
例1:没有文件路径时
例2:有文件路径时
4.文件的顺序读写
用于文件读写的几个函数
fputc函数
函数的原型
int fputc ( int character, FILE * stream );
字符 文件指针
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "w");
'w'书写文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}
fputc('\n', pf);
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
运行结果:
fgetc函数
函数的原型
int fgetc ( FILE * stream );
指针文件
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "r");
'r'读取文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int i = 0;
//fputc('a', pf);
char ch = fgetc(pf);
printf("%c", ch);
return 0;
}
运行结果:
fgets函数
函数原型
char * fgets ( char * str, int num, FILE * stream );
字符串的首地址 最多读取几个字符 文件指针
最多读取n-1个,后面补\0 ,且读到\0会停止。其他所有字符都会读取
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "r");
char arr[] = { "#########" };
fgets(arr, 5, pf);
printf("%s", arr);
fclose(pf);
pf = NULL;
return 0;
}
文件里面的数据:
监视结果:
fputs函数
函数原型
int fputs ( const char * str, FILE * stream );
字符串首地址 文件指针
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "w");
char arr[] = { "abcdefghi" };
fputs(arr, pf);
fputs("\n", pf);
fputs("abcdef,pf);
fclose(pf);
pf = NULL;
return 0;
}
运行结果
fprintf函数
函数原型
int fprintf ( FILE * stream, const char * format, ... );
我们对比一下它与scanf的区别
int printf ( const char * format, ... );
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "w");
char arr[20] = { "#########" };
fprintf(pf, "%s\n %d\n %c\n", arr, 5, 'c');
pf = NULL;
return 0;
}
运行结果
fscanf函数
函数原型
int fscanf ( FILE * stream, const char * format, ... );
对比一下scanf函数
int scanf ( const char * format, ... );
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "r");
char arr1[10] = { 0 };
int c = 0;
char b = 0;
fscanf(pf,"%s %d %c",arr1,&c,&b);
printf("%s\n%d\n%c\n", arr1, c, b);
pf = NULL;
return 0;
}
这里我们用的是上面fpintf应用时存放的数据
fwrite函数
函数原型
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
一片连续空间的指针 单个要读取的元素的字节数 要读取的元素个数 文件指针
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "w");
int arr1[] = { 0,1,2,3,4,5,6,7 };
fwrite(arr1, sizeof(int), 8, pf);
pf = NULL;
return 0;
}
运行结果
fread函数
函数原型
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
一片连续空间的指针 单个要读取的元素的字节数 要读取的元素个数 文件指针
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "r");
int arr1[10] = { 0 };
fread(arr1, sizeof(int), 8, pf);
int i = 0;
for (i = 0; i < 8; i++)
{
printf("%d ", arr1[i]);
}
fclose(pf);
pf = NULL;
return 0;
}
建立在上面fwrite上的运行结果
补充
前面我们注意到下面这些函数适合所有输入输出流
那么他们怎么作用于标准输入输出流呢?
接下来我们尝试用fscanf来实现标准输入流,其他适用所有流的函数都类似。
int main()
{
int a = 0;
char b = 0;
char arr[10] = { 0 };
fscanf(stdin, "%d %s %c", &a, arr, &b);
printf("%d\n%s\n%c", a, arr, b);
return 0;
}
运行结果:
5.文件的随机读写
fseek函数
这个函数可以根据文件指针的位置和偏移量来定位文件指针
函数原型
int fseek ( FILE * stream, long int offset, int origin );
文件指针 偏移量 文件起始位置
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdefgh", pf);
fseek(pf, 4, SEEK_SET);
fputs("hh", pf);
fclose(pf);
pf = NULL;
return 0;
}
运行结果
ftell函数
返回文件指针相对于起始位置的偏移量
函数原型
long int ftell ( FILE * stream );
函数的应用
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdefgh", pf);
long a = ftell(pf);
printf("%ld\n", a);
fseek(pf, 4, SEEK_SET);
long b = ftell(pf);
printf("%ld", b);
fputs("hh", pf);
fclose(pf);
pf = NULL;
return 0;
}
运行结果
rewind函数
文件指针返回文件的起始位置
这个函数太简单,就不详细介绍了
void rewind ( FILE * stream );
谢谢大家的阅读!