一,程序文件的基础概述
1,文件的打开与关闭的系统原理
在平常中我们的输入和输出都是输出在计算机屏幕上,而其实数据也可以输出到文件中,也可从文件中输入数据。
首先,C/C++程序中运用fopen打开一个文件,而打开文件有使用绝对路径和相对路径两种方式,然后用文件指针FILE的形式来接受文件,FILE会将文件数据存放到专属存放文件的文件信息区里,文件信息区是打开每个文件所生成的存放文件数据的一块内存区域,而文件指针就是指向这块区域,从而调用这块区域的数据,然后就是对文件进行一系列的读写或其他操作,最后就是关闭文件。如图所示(图中用相对路径来打开文件):
2,数据流形式
流是一种抽象的概念,比如水流,电流等同理,然而在计算机的运行的各种数据也存在数据流,在C程序中,只要运行起来就默认打开三个流:标准输入流stdin,标准输出流stdout,标准错误流stderr,而一但将文件操作和程序联系起来将不再使用标准输入输出流了。有关文件操作的一系列函数如下:
3,文件的概述
文件划分其实有很多种类,在C程序中,我们主要从文件的编码方式来看。从文件的编码方式中文件可划分为文本文件和二进制文件两种。文本文件在磁盘中存储时每个字符对应一个比特位,即用ASCII码的字符形式存储。这种存储方式是计算机展现给人们能够看懂的。二进制文件在程序中都是以二进制的形式存储的,里面的内容是我们看不懂的,机器处理二进制文件时将其看成字符流,按字节进行处理,在内部处理后能成为机器能够识别的码。
二,文件函数的操作
1,文件的打开与关闭
打开文件用函数fopen,fopen会从文件缓冲区里拿到数据,如若打开成功会返回文件缓冲区的首地址,如若打开失败会返回NULL,打开失败的原因大多情况下是在此路径下没有此文件或路径错误。而打开文件时,若是文件的路径在此源程序下可直接写文件名,此为相对路径;若是在其它目录下要写全文件路径,此为绝对路径。
当文件路径问题解决后就要说明要对文件进行什么操作。"r"表示只对文件进行读,"w"表示只对文件进行写,若在此路径下不存在此文件,则在此路径下将会自动建立此文件,"rb"表示只对二进制文件进行读,"wb"表示只对二进制文件进行写,若在此路径下不存在此文件,则在此路径下将会自动建立此文件,.....这几个是常用的操作。
关闭文件用函数fclose,此操作很简单,具体代码如下:
#include<stdio.h>
int main()
{
//此处应注意,打开文件是绝对路径,若文件在此项目录下,可以用相对目录打开
FILE* pr=fopen("E:\\text\\test1.txt","w");//往文件中写入,若不存在此文件,则在此路径中建立此文件
if (pr == NULL)
{
printf("兔子兔子");//当打开失败时的提示
exit(0);
}
fclose(pr);//关闭文件
pr = NULL;
return 0;
}
2,文件字符的输入与输出
文件输入函数的形式为int fgetc(FILE* pa),返回值为文件指针此时指向文件的具体位置(注意:这里说的指针并不是地址形式,而是指向数据的具体位置,刚开始的时候指向开头位置,即0,往后移动一位就加一),参数适用于所有流的形式,即即可往文件里输入,又可在标准输入流stdin中输入。
文件的输出函数形式为int fputc(int ch, FILE* pa),返回值仍为文件指针此时指向文件的具体位置。fputc是把ch输出到pa流中,pa适用于所有流。
注意,当用完fgetc和fputc时,此时指向文件数据位置的指针就自动会往下一个单元位置前进一位。具体代码如下:
代码一:
#include<stdio.h>
int main()
{
int a = 10000;
char b[15] = "zhujunhao";
FILE* pr=fopen("E:\\text\\test1.txt","w");
if (pr == NULL)
{
printf("兔子");
exit(0);
}
fputc(a,pr);//此数不可以用b,因为fput(a,pr);a只能是一个字符或一个数
fputc('j', pr);//不能添加字符串
fputc('h', pr);
fclose(pr);
pr = NULL;
return 0;
}
代码二:
#include<stdio.h>
int main()
{
FILE* pa =fopen("E:\\text\\test1.txt","r");
printf("%c", fgetc(pa));//fgetc(pa)从文件中的第一个开始读取,先从第一个读取
printf("%c", fgetc(pa));//fgetc(pa)从文件中自动读取第二个
//printf("%c", fgetc(pa));//fget(pa)从文件中自动读取第三个
fclose(pa);
pa = NULL;
return 0;
}
代码三:
#include<stdio.h>
int main()
{
int ch = fgetc(stdin);//stdin指从键盘中输入,stdin是标准输入流,即键盘
fputc(ch,stdout);//stdout指从键盘中输出,stdin是标准输出流,即屏幕
return 0;
}
3,文本的输入和输出
文本行的输入函数形式为char * fgets ( char * str, int num, FILE * stream ),FILE*参数中也是适用于所有流,函数的功能是从FILE*流中得到num个字节放入数组str中。
#include<stdio.h>
int main()
{
char arr[50];
FILE* pr = fopen("E:\\text\\test1.txt","r");
if (pr == NULL)
{
printf("兔子");
exit(1);
}
fgets(arr, 50, pr);//在fgets中,第一个arr是将pr中读取的放到arr中,第二个50指最多读取50个字节,第三个pr指从pr中读取
printf("%s", arr);//注意:这里最多只能读取一行
fgets(arr, 50, pr);//第一行数据结束后后有字符\n,所以在读取中也把\n读取到里面了,第二次可不用加\n即自动换行
fclose(pr);
pr = NULL;
return 0;
}
文本行的输出函数形式为int fputs ( const char * str, FILE * stream );FILE*参数中也是适用于所有流,函数的功能是将数组str直接全部输出到stream流中。
#include<stdio.h>
int main()
{
FILE* pr = fopen("E:\\text\\test2.txt", "w");
char a[15] = "aaa";
if (pr == NULL)
{
printf("兔子");
exit(0);
}
fputs(a,pr);//fputs可以添加许多个,fputc只能添加一个有关字符或者数
fputs("zhujunhao", pr);//fputs可以添加字符串也可以添加字符,fputc只能添加字符
fclose(pr);
pr = NULL;
return 0;
}//总结:对于fputs比fputc更为高级,最好用fputs,可助记为s为字符串,c为字符
4,文件的格式化输入于输出
文件的格式化输入函数标准形式为int fscanf ( FILE * stream, const char * format, ... );此函数与scanf函数就多了一步控制流,此函数的功能是将函数参数输出到指定流中。fprintf函数与printf函数同理,具体代码如下:
代码一:
#include<stdio.h>
int main()
{
int a = 666, b = 999;
char arr[50] = "tuzi";
FILE* pa = fopen("E:\\text\\test2.txt", "w");
if (pa == NULL)
{
printf("兔子");
exit(1);
}
fprintf(pa, "%d %s %d", a, arr, b);//将a,arr,b全部输出到pa所指向的文件中
fclose(pa);
pa = NULL;
return 0;
}
代码二:
#include<stdio.h>
int main()
{
char ar[100];
int a, b;
FILE* pa = fopen("E:\\text\\test1.txt", "r");
if (pa == NULL)
{
printf("兔子");
exit(1);
}
fscanf(pa, "%s %d %d", ar, &a, &b);//从文件中输入ar,a,b这三个数据,但是文件中必须有这三个类型的数据
printf("%s %d %d", ar, a, b);
fclose(pa);
pa = NULL;
return 0;
}
代码三:
#include<stdio.h>
int main()
{
char ar[50], arr[50];
int a;
fscanf(stdin,"%s %d %s",ar,&a,arr);//从输入设备中输入这三个类型的数据
fprintf(stdout,"%s %d %s",arr,a,ar);//从输出设备中输出这三个数据
return 0;
}//注意:不是每个函数都可以输入到输入设备中或者输出到输出设备中,必须函数满足所以的流才可以
5,文件的读写
文件的输入函数size_t fread ( void * ptr, size_t size, size_t count, FILE * stream )和输出函数size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream )都是以二进制形式来输入和输出的。其中stream不适用于所有流,只适用于文件。两函数是将count个数据ptr中的size字节输入或输出文件流stream中。具体代码如下:
代码一:
#include<stdio.h>
struct p
{
char a[50];
char b[50];
char c[50];
}ar = {"abc","sss","99"},tm;
int main()
{
char A[500];
gets(A);
FILE* pa = fopen("E:\\text\\test1.txt", "wb");
if (pa == NULL)
{
printf("兔子");
exit(1);
}
fwrite(&ar, sizeof(ar), 1, pa);//fwrite函数是往二进制的形式写文件,其中第一个空为要写入的数据地址
fwrite(A,sizeof(A),1,pa);//第二个空为写入数据所占用内存大小,第三个空为要写几个A,第四个为写进的文件指针
fclose(pa);
pa = NULL;
return 0;
}
代码二:
#include<stdio.h>
int main()
{
char a[500],b[500];
FILE* pa = fopen("E:\\text\\test2.txt", "r");//文件数据为abcdefg数据长度为7
if (!pa)
{
perror("兔子");
exit(1);
}
//对于fread和fwrite函数返回值,若其中写入或读入的数已经超出文件数据中的最后一个时,则返回的值会是读或写入时最大的n值
printf("%d\n", fread(a, sizeof(char), 2, pa));//将2个char大小的数据读入a中,即两个字符,返回值为2
printf("%c\n", a[0]);//此时a[n]={'a','b'};
printf("%d\n", fread(b, 4, 1, pa));//此时b[n]={'c','d','e','f'},共四个,在用完fread或fwrite后文件指向会自动移动
for (int i = 0; i < 4; i++)
printf("%c", b[i]);
//注意:不能用puts(b),因为以为fread和fwrite是用于二进制文件,puts会把乱码打印出来
fclose(pa);
pa = NULL;
return 0;
}
代码三:
#include<stdio.h>
int main()
{
FILE* pa = fopen("E:\\text\\test2.txt", "w");
if (!pa)
{
perror("兔子");
exit(1);
}
char a[5] = { '1','2','3','4','5'};
fwrite(a, sizeof(char), 1, pa);//只将第一个字符'1'写入进去了,此时文件中数据为1
fwrite(a, sizeof(a), 1, pa);//将数组a全部元素写入进去了,因为sizeof(a)即为全部元素所占的内存大小
fclose(pa);//此时文件中数据为11234
pa = NULL;
return 0;
}
6,文件的定位
在C/C++程序中,有个文件定位函数——fseek()函数,函数形式为int fseek ( FILE * stream, long int offset, int origin );其中,当origin宏的名字为SEEK_SET(数值为0)时,此时表示文件的开始;当origin宏的名字为SEEK_CUR(数值为1)时,此时表示文件当前位置的起点;当origin宏的名字为SEEK_CUR(数值为2)时,此时表示文件末尾的位置。stream为文件流,offset表示偏移量。而当函数操作成功时返回数值0,操作失败时返回非零值。在这里需提醒的是偏移位置的定位,具体说明和代码如下:
#include<stdio.h>
int main()
{
FILE* pa = fopen("E:\\text\\test3.txt", "r");//文件中的数据为123456789abcdef
if (!pa)
{
puts("兔子");
exit(1);
}
fseek(pa, 1, SEEK_SET);//pa是文件指针,1表示偏移1个数据(第二个数据,刚开始偏移量为0)即偏移1位
printf("%c", fgetc(pa));//其中,SEEK_SET是指向开始位置,SEEK_END指向最后一个位置,SEEK_CUR指向当前的位置
fclose(pa);
pa = NULL;
return 0;
}//注意:对于fseek(pa,-1,SEEK_END)为最后一个字符,默认最后偏移量为-1,偏移量不能为正数