====标准IO
标准IO:由标准C库提供的函数接口
头文件:stdio.h
常用的文件操作接口:
1、打开文件:fopen
函数原型:
FILE *fopen(const char *path, const char *mode );
参数:
const char *path:要打开的文件的路径名
const char *mode:以什么方式打开文件
- r 以只读的方式打开,且定位在文件开头
- r+ 以可读可写的方式打开,且定位在文件开头
- w 以只写的方式打开文件,如果文件存在就清空,不存在就创建,定位在文件开头
- w+ 以可读可写的方式打开文件,如果文件存在就清空,不存在就创建,定位在文件开头
- a 以只写且追加的方式打开文件,如果文件不存在就创建,定位在文件末尾
- a+ 以可读可写的方式打开文件,如果文件不存在就创建,如果是读取文件则定位在文件开头,如果是写入则定位在文件末尾
返回值:
成功:FILE *指针,文件流指针
失败:NULL
2、关闭文件:fclose
int fclose(FILE *stream);
参数:要关闭文件的流指针
3、读取文件:fread
函数原型:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
void *ptr:保存读取数据的内存的地址
size_t size:每一块数据的字节数
size_t nmemb:要读取的块数
FILE *stream:文件流指针
返回值:
成功:读取的块数
失败:小于读取的块数
思考:设两个文件分别有24字节和21字节,按每块5字节的方式读取5块数据,返回值为多少?
结果:返回值为4,但还是读取了24字节和21字节
原因:fread的返回值只返回读满的块数,没有读满的不算一块
4、写入文件:fwrite
函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
const void *ptr:保存要写入的数据的内存的地址
size_t size:每一块数据的字节数
size_t nmemb:要写入的块数
FILE *stream:文件流指针
返回值:
成功:写入的块数
失败:小于写入的块数
思考:设buf中有24字节和21字节两种情况,按每块5字节的方式写入5块数据,结果如何?
结果:返回值为5,多写入NULL数据或乱码
5、移动光标:fseek
函数原型:
int fseek(FILE *stream, long offset, int whence);
参数:
FILE *stream:文件流指针
long offset:偏移量(>0 <0 =0)
int whence:从哪里开始偏移
SEEK_SET 文件开头
SEEK_CUR 光标当前
SEEK_END 文件末尾
返回值:
成功:0
失败:-1
6、获取光标距离文件开头位置:ftell
函数原型:
long ftell(FILE *stream);
参数:
FILE *stream:文件流指针
返回值:
成功:光标当前距离文件开头的字节数
失败:-1
练习:使用标准IO函数实现文件的复制
7、判断文件是否到达末尾:feof
int feof(FILE *stream);
返回值:
光标位于文件末尾:1
光标没有到达文件末尾:0
==============================
常用数据输入输出函数:
思考:printf的双引号中没有\n时,内容能否输出?
不能正常输出,直到遇到\n才会输出,或者在程序结束,清空缓冲区是才会被输出
原因:printf的缓冲区是行缓冲机制,即遇到换行符才输出一次
缓冲区的三种机制:
全缓冲:当缓冲区全满以后才输出
行缓冲:遇到换行符才输出:printf、scanf
无缓冲:直接输出,不停留:perror
printf家族:
printf:往标准输出缓冲区进行输出
fprintf:往文件中输出内容
sprintf:往字符串中输出
往文件中输出:
函数原型:
int fprintf(FILE *stream, const char *format, …);
参数:
FILE *stream:要输出对象的文件流指针
const char *format:以字符串的形式输出
…:变参函数的标志,表示后面的参数个数及类型由前面的参数决定
引用场合:
将不同类型的数据以字符串的形式保存到文件中
补充:三个标准文件,即进程初始化时就会打开的三个文件的文件流指针
标准输入(stdin)、标准输出(stdout)、标准出错(stderr)
往字符串中输出
这里的字符串指的是字符型数组,如果填字符型指针,那么这个指针必须指向的是可写入数据的内存地址
函数原型:
int sprintf(char *str, const char *format, …);
参数:
char *str:一个可输入数据的内存的地址
const char *format:要输出的数据
…:如果有格式控制符就要添加对应类型的变量
应用场合:
将不同类型的数据拼接成一个字符串,并保存到一个字符型数组中
scanf家族:
scanf:从标准输入缓冲区中获取数据保存到对应的变量中
fscanf:从文件中获取数据保存到对应类型的变量中
sscanf:从字符串中获取数据保存到对应类型的变量中
提取文件数据:fscanf
int fscanf(FILE *stream, const char *format, …);
参数:
FILE *stream:文件流指针
const char *format:要输入的格式
…:根据格式控制符来决定变量的数量及类型
补充:
scanf中遇到空格是算作一次输入,如果要将空格一起获取,可以使用这个格式控制符:%[^\n]
这样一来,只有输入了\n才算一次输入的结束
拆分字符串:sscanf
int sscanf(const char *str, const char *format, …);
参数:
const char *str:要进行拆分的字符串
const char *format:按什么格式拆分
…:保存拆分出的数据的变量
思考:有字符串:“hello-123-3.14"和字符串"123-3.14-hello”,试着拆分这两个字符串
结果:前一个字符串不能拆分,后一个字符串可以拆分,因为前一个字符串在获取hello这部分时,
将后面的’-'当做了字符串的一部分,所以连带着后面的也一起获取了
总结:要拆分的字符串中如果有子串存在,要注意这个子串和其他数据之间只能用空格或\n隔开
练习:做一个简单的管理系统,有注册功能,将数据保存到一个文件里面,运行程序都能读取文件内容
#include<stdio.h>
#include<stdlib.h>
#include <strings.h>
#include <string.h>
#define ACCOUNT_INIT 2000
typedef unsigned int uint;
typedef struct list{
uint account;
char number[15];
char password[15];
struct list *next;
}List,*LIST;
/*
description: Create a head node
return value: head address
*/
LIST creat_head()
{
LIST head = (LIST)malloc(sizeof(List));
if(head==NULL)
{
printf("head malloc failed!");
return NULL;
}
head->next=NULL;
return head;
}
/*
description: Create a node
return value: node address
*/
LIST creat_node(uint account,char *number,char * password)
{
LIST node = (LIST)malloc(sizeof(List));
if(node==NULL)
{
printf("head malloc failed!");
return NULL;
}
node->account=account;
stpcpy(node->number,number);
stpcpy(node->password,password);
node->next=NULL;
return node;
}
/*
description: Insert from the head into the linked list
*/
void push_head(LIST head,LIST node)
{
node->next=head->next;
head->next=node;
}
/*
description: Insert from the tail into the linked list
*/
void push_tail(LIST head,LIST node)
{
LIST p=head;
while(p->next!=NULL)
{
p=p->next;
}
p->next=node;
}
/*
description: Register an account using number
*/
void register_account(LIST head,char *number,char *password)
{
LIST p =head;
uint account;
if(p->next==NULL)
{
account=ACCOUNT_INIT;
}
else
{
while(p->next!=NULL)
{
p=p->next;
}
account = p->account+1;
}
LIST node = creat_node(account,number,password);//Create a new node
push_tail(head,node);//Insert node into linked list
}
void show(LIST head)
{
LIST p=head->next;
while(p!=NULL)
{
printf("%d %s %s\n",p->account,p->number,p->password);
p=p->next;
}
}
void display()
{
printf("==================\n");
printf("1、register\n2、quit\n3、display list\n");
}
/*
description: List Initialization
*/
FILE * list_Init(LIST head)
{
LIST node = NULL;
uint account=0;
char number[15]={0};
char password[15]={0};
char *str=malloc(50);
FILE *fb=fopen("4.txt","r+");
if(fb==NULL)
{
printf("file open error\n");
return NULL;
}
//fseek(fb,0,SEEK_SET);
while(fscanf(fb,"%[^\n]\n",str)==1)
{
sscanf(str,"%d %s %s",&account,number,password);
node =creat_node(account,number,password);
push_tail(head,node);
account=0;
bzero(number,sizeof(number));
}
free(str);
return fb;
}
/*
description: Save data in a file
*/
void save(LIST head,FILE *fb)
{
fseek(fb,0,SEEK_SET);
LIST p=head->next;
while(p!=NULL)
{
fprintf(fb,"%d %s %s\n",p->account,p->number,p->password);
p=p->next;
}
fclose(fb);
}
int main()
{
LIST head =creat_head();
FILE *fb=list_Init(head);
int key=0;
char number[15]={0};
char password[15]={0};
while(1)
{
display();
scanf("%d",&key);
if(key==1)
{
printf("please input a phone number and your account password");
scanf("%s %s",number,password);
register_account(head,number,password);
bzero(number,sizeof(number));
}
else if(key==2)
{
save(head,fb);
break;
}
else if(key==3)
{
show(head);
}
}
}