今天主要讲一下这四个函数接口:fwrite、fread、fprintf、fsancf以及流的定位:ftell、rewind、fseek
函数接口
fwrite
fwrite:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
向流中写入number个对象,每个对象size字节大小,在ptr指向的空间中
参数:
ptr:存放数据空间的首地址
size:每个数据对象的大小
number:数据对象的个数
stream:文件流指针
返回值:
成功返回写入对象的个数
失败返回0
读到文件末尾返回0
例子:向file.txt文件中传入学生类型的结构体数据
#include<stdio.h>
typedef struct student{ //定义结构体
char name[20];
char sex;
int age;
int score;
}stu_x;
int main(void) //主函数
{
stu_x a = {"tom",'m',19,70}; //输入数据
stu_x b = {"zero",'f',20,100};
stu_x c[3] = {
{"jack",'m',18,95},
{"john",'f',19,80},
{"lucky",'m',20,65},
};
FILE *fp = NULL;
fp = fopen("file.txt","w"); //以写的方式打开文件
if(NULL == fp)
{
perror("fail to fopen!");
return -1;
}
fwrite(&a,sizeof(stu_x),1,fp);
fwrite(&b,sizeof(stu_x),1,fp);
fwrite(c,sizeof(stu_x),3,fp);
fclose(fp);
return 0;
}
数据已经写入文件中,但是cat只能显示ASCII码文件,不能显示二进制文件。
fread
fread:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
从流中读取nmemb个对象,每个对象size个字节,存放到ptr指向的空间中
参数:
ptr:存放读取内容空间首地址
size:读取对象的大小
nmemb:读取对象的个数
stream:文件流指针
返回值:
成功返回读到对象个数
失败返回0
读到文件末尾返回0
我们可以将刚刚写入进去的数据重新读取出来:
#include<stdio.h>
typedef struct student //fread读取数据的话,必须得要有数据的结构体
{
char name[20];
char sex;
int age;
int score;
}stu_t;
int ShowStuInfo(stu_t tmpstu) //以这种方式输出
{
printf("name = %s\n",tmpstu.name);
printf(" sex = %c\n",tmpstu.sex);
printf(" age = %d\n",tmpstu.age);
printf("score = %d\n",tmpstu.score);
}
int main(void)
{
FILE *p = NULL;
size_t ret;
int i = 0;
stu_t a;
stu_t b[10];
p = fopen("file.txt","r");
if(NULL == p)
{
perror("fail to fopen");
return -1;
}
fread(&a,sizeof(stu_t),1,p); //取a的地址
ShowStuInfo(a);
ret = fread(b,sizeof(stu_t),10,p); //取数组b的地址,ret可以看到文件中还有几组数据
for(i = 0;i < ret;++i)
{
ShowStuInfo(b[i]);
}
fclose(p);
return 0;
}
结果:
我们可以看到,再进行第二个fread时,我们写入的读取对象的个数是10,但是实际上只有4个,所以最后ret等于4。
fprintf
fprintf
int fprintf(FILE *stream, const char *format, ...);
功能:
将格式化字符串输出到stream指向的流中
我的个人观点,认为这个实际上跟printf一样,只不过输入时需要加文件流指针,下面举一个例子:
#include<stdio.h>
int main(void)
{
FILE *p = NULL;
int Num1 = 100;
int Num2 = 200;
p = fopen("file.txt","w");
if(NULL == p)
{
perror("fail to fopen");
return -1;
}
fprintf(p,"hello world!\n num1 = %d , num2 = %d\n",Num1,Num2); //将值输入到文件中
fclose(p);
return 0;
}
fscanf
fsancf
int fscanf(FILE *stream, const char *format, ...);
功能:
从流中读取格式化的字符串
我们可以将文件中的数据进行提取出来。
第二部分就是流的定位
ftell
ftell
long ftell(FILE *stream);
功能:
获得流的偏移量
在进行第一次打开文件时,流的偏移量是0
rewind
rewind
void rewind(FILE *stream);
功能:
将流的偏移量重新设置到开头
fseek
fseek
int fseek(FILE *stream, long offset, int whence);
功能:
设置流的偏移量
参数:
stream:文件流指针
offset:偏移量
> 0 向后偏移
< 0 向前偏移
whence:
SEEK_SET 文件开头
SEEK_CUR 文件当前位置
SEEK_END 文件末尾
我们可以做一个简单的例子,方便于了解
#include<stdio.h>
int main(void)
{
FILE *src = NULL;
src = fopen("file.txt","w");
if(NULL == src)
{
perror("fail to fopen");
return -1;
}
fseek(src,10,SEEK_SET); //在文件开头位置向右偏移10
fputc('a',src);
fseek(src,-5,SEEK_CUR); //在文件当前位置向左偏移5
fputc('c',src);
fseek(src,0,SEEK_SET); //回到文件开头位置
fputc('b',src);
fclose(src);
return 0;
}
结果:
以上就是今天的所以内容,下面进行一个实例,从终端输入一个单词,获得单词的含义。
#include<stdio.h>
#include<string.h>
int main(void)
{
FILE *src = NULL;
src = fopen("dict.txt","r");
char word[256] = {0};
char tmpbuff[4096];
char *ptmp = NULL;
char *pret = NULL;
printf("please input one word:");
gets(word);
if(NULL == src)
{
perror("fail to fopen");
return -1;
}
while(1) //进行死循环
{
pret = fgets(tmpbuff,sizeof(tmpbuff),src); //在源文件中,每一行结尾都有\n,所以我们可以使用fgets获得每一行的首地址,让pret进行记录
//tmpbuff是存放字符串空间首地址,读取4096个字节,要保证足够大
if(NULL == pret) //判断是否读到文件末尾
{
break;
}
ptmp = tmpbuff;
while(*ptmp != ' ' && *ptmp != '\0') //截取单词
{
++ptmp;
}
*ptmp = '\0'; //将第一个空格的位置换成\0
ptmp++;
while(*ptmp == ' ')
{
++ptmp;
}
if(strcmp(word,tmpbuff) == 0) //进行字符串判断,看是否与输入的字符串相等
{
printf("word = %s\n",word); //输出单词
printf("ptmp = %s",ptmp); //输出含义,因为已经截断了,所以ptmp当前的首地址是含义的地址
return 0;
}
}
fclose(src);
printf("Word does not exist!\n");
return 0;
}
结果: