目录
这里对stdin以及它的亲属stdout、stderr进行补充:
一、文件的结构
1、文件指针的结构
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
2、文件读写操作的结构
我们所说的文件操作便是围绕着这个结构来进行的,一般来说,可以通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。即:
FILE* pf;//文件指针变量
大概的操作读写操作如下:
由此可见文件指针是用来找这个文件信息区的。当我们打算读写一个文件时,我们进行的操作:1、打开文件。2、被打开的文件就维护了一个文件信息区。而信息区中又有很多个不同的文件,那么我们的指针也可以通过一些方法来访问这些文件,详见第二小点。例如:其中有一个data.txt的文件,如下:
二、文件的基本操作
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件
//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );
实例:
/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开文件
pFile = fopen ("myfile.txt","w");
//文件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile); //此操作为将文本行(即fopen example)输出到文件中
//关闭文件
fclose (pFile);
pFile=NULL;
}
return 0;
}
对此我们可以将文件的操作分为三大块:1、打开文件。2、对文件操作。3、关闭文件。
其中有两大块基本上是固定的,分别为“打开文件”以及“关闭文件”操作。
我们可以参照以下的公式来写:
//打开文件
FILE * pf;
pf = fopen(“文件名或者文件路径”,“文件打开方式”);
if(pf==NULL)
{
perror(“fopen”);
return;
}
//->文件操作
//<-
//封闭文件
fclose(pf);
pf=NULL;
我们只需要对其中文件操作进行修改即可!
打开文件中的的操作
1、文件打开方式
打开一个只写的文件:
pFile = fopen ("myfile.txt","w");
//这里不管有无myfile.txt都可建立,如果有则对立面的数据进行操作,无则建立一个新的文件。
//ps:可以指定路径,此为默认。
打开一个只读的文件:
pFile = fopen ("myfile.txt","r")//这里如果myfile.txt未建立过则会出错。这里我们可以在相应的路径下直接创建相应关键字的文件来解决这个问题。
2、文件名或者路径名
比如我要打开这个路径下的contact.dat文件
我可以这样操作 pFile = fopen(“contact.dat”,“文件打开方式”);
也可以这样操作pFile = fopen(“E:\\gitee相关软件\\practice_c\\txulu”,“文件打开方式”);//这里多了\是取消转意的效果
对此我们称“contact.dat”这种路径打开文件的方式为相对路径->即在当前程序路径底下的。
“E:\\gitee相关软件\\practice_c\\txulu”为绝对路径->这个文件可以在任何位置。
对于相对路径我们也有拓展:
如果想在上一路径底下创建文件我们可以用 . 这个来修饰 . 叫当前目录,上一级目录是 .. 我们如果要把以上contact.dat文件放到x64文件里面去的话可以这样操作:“.\\x64\\contact.dat”,如果放到上一级目录的x64中则为:“..\\x64\\contact.dat”
好了!Y(^o^)Y 了解了这么多基本操作,那么我们就进入正题吧!真正的连贯实现文件操作!
三、文件操作之顺序读写
常用的操作
看到这里有人就要问了输入输出流是啥?这个流其实是传输数据的通道。它能传输数据将数据从别的地方,如内存,文件等地方传输给程序或将程序中的数据传输到别的地方。
这里对输入输出做一个补充:
一张图就能明白:
1、fgetc
它的作用是从流中获取字符。
原型:int fgetc ( FILE * stream );
/* fgetc example: money counter */
#include <stdio.h>
int main()
{
FILE* pFile;
int c;
int n = 0;
pFile = fopen("myfile.txt", "r");
if (pFile == NULL)
perror("Error opening file");
else
{
do {
c = fgetc(pFile);
if (c == '$') n++;
} while (c != EOF);
fclose(pFile);
pFile = NULL;
printf("The file contains %d dollar sign characters ($).\n", n);
}
return 0;
}
2、fputc
它的作用是将字符写入流。
原型:int fputc ( int character, FILE * stream );
#include <stdio.h>
int main()
{
FILE* pFile;
char c;
pFile = fopen("alphabet.txt", "w");
if (pFile != NULL) {
for (c = 'A'; c <= 'Z'; c++)
fputc(c, pFile);
fclose(pFile);
pFile = NULL;
}
return 0;
}
3、fgets
它的作用是从流中获取字符串。
当fgets函数成功读取到一行数据时,它会返回一个指向str的指针。如果到达了文件结尾或者发生了错误,它会返回一个空指针。注意:fgets函数会将读取到的换行符'\n'也存储到字符数组中。如果文件中的一行数据超过了指定的n个字符,fgets会截断这一行数据,并在最后一个字符后添加一个'\0'字符。
原型:char * fgets ( char * str, int num, FILE * stream );
//其中,str是一个字符数组,用来存储读取到的一行数据;num是一个整数,表示最多读取的字符数,
//包括字符串结尾的'\0';stream是一个文件指针,用来指定从哪个文件中读取数据。
/* fgets example */
#include <stdio.h>
int main()
{
FILE* pFile;
char mystring[100];
pFile = fopen("myfile.txt", "r");
if (pFile == NULL) perror("Error opening file");
else {
if (fgets(mystring, 100, pFile) != NULL)
puts(mystring);
fclose(pFile);
pFile=NULL;
}
return 0;
}
4、fputs
它的作用是将字符串写入流。
原型:int fputs ( const char * str, FILE * stream );
/* fputs example */
#include <stdio.h>
#include<stdlib.h>
int main()
{
FILE* pFile;
char sentence[256];
printf("Enter sentence to append: ");
fgets(sentence, 256, stdin);//stdin是啥?别急往下滑,下面有补充!
pFile = fopen("mylog.txt", "a");
fputs(sentence, pFile);
fclose(pFile);
pFile = NULL;
return 0;
}
这里对stdin以及它的亲属stdout、stderr进行补充:
一张图:
stdin:将键盘上输入的信息输出到文件或者其他地方
stdout:将文件或者别处的信息输出到屏幕
stderr:将错误信息输出到屏幕
5、fread
它的作用是从流中读取数据块。
原型:size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
//其中,ptr是指向要写入数据的指针,size是每个数据块的字节数,count是要写入的数据块的数量,
//stream是指向FILE结构体的指针,表示要写入的文件
#include<stdio.h>
struct S
{
int a;
float s;
char str[10];
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fread(&s, sizeof(struct S), 1, pf);
printf("%d %f %s\n", s.a, s.s, s.str);
fclose(pf);
pf = NULL;
return 0;
}
6、fwrite
它的作用是写入要流式传输的数据块
原型:size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
//ptr为要写入的数据的指针,size为每个数据项的大小,count为要写入的数据项的个数,
//stream为文件指针。
#include<stdio.h>
struct S
{
int a;
float s;
char str[10];
};
int main()
{
struct S s = { 99, 6.18f, "bit" };
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fwrite(&s, sizeof(struct S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
四、文件操作之随机读写
1、fseek
它的作用是根据文件指针的位置和偏移量来定位文件指针。
原型:int fseek ( FILE * stream, long int offset, int origin );
/* fseek example */
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ( "example.txt" , "wb" );
fputs ( "This is an apple." , pFile );
fseek ( pFile , 9 , SEEK_SET );
fputs ( " sam" , pFile );
fclose ( pFile );
return 0;
}
//这里将原来为This is an apple.从开头数第10位后变成了 sam
2、ftell
它的作用是返回文件指针相对于起始位置的偏移量。
原型:long int ftell ( FILE * stream );
/* ftell example : getting size of a file */
#include <stdio.h>
int main ()
{
FILE * pFile;
long size;
pFile = fopen ("myfile.txt","rb");
if (pFile==NULL) perror ("Error opening file");
else
{
fseek (pFile, 0, SEEK_END); // 这里是从末尾开始
size=ftell (pFile);
fclose (pFile);
pFile=NULL;
printf ("Size of myfile.txt: %ld bytes.\n",size);//myfile.txt文件中的内容为$$因此可知为2
}
return 0;
}
3、rewind
它的作用是让文件指针的位置回到文件的起始位置。
原型:void rewind ( FILE * stream );
/* rewind example */
#include <stdio.h>
#include<stdlib.h>
int main()
{
int n;
FILE* pFile;
char buffer[27];
pFile = fopen("myfile.txt", "w+");
for (n = 'A'; n <= 'Z'; n++)
fputc(n, pFile);//一个一个将26个大写字母写入
rewind(pFile);//将指针返回首部
fread(buffer, 1, 26, pFile);//读出数据
fclose(pFile);
pFile = NULL;
buffer[26] = '\0';
puts(buffer);
return 0;
}
感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!