标准IO的学习
一、标准IO的概述:
标准IO和文件IO的执行流程的区别:
文件IO:直接调用内核提供的系统调用函数,头文件是:ubistd.h
标准IO:间接调用系统调用函数,头文件是:stdio.h
与文件IO类似,都是操作一些文件操作函数,主要区别在于标准IO是用来操作普通文件的。
Linux平台总共的文件类型有7种:
- 普通文件
b 块设备
c 表示的是字符设备
d 表示目录
l 表示链接文件
s 表示套接字文件
p 表示管道文件
二、标准IO的特性
2.1文件ID
标准IO的文件ID,(注意:文件IO的时候,open()函数,返回值 int fd---表示文件的描述符),
文件流指针,它的表示方式为FILE *fd(不是NULL)。
标准IO的执行流程:
和文件IO操作流程基本一致。
第一步:先打开文件(获取文件的ID来识别相应的文件),接下来再对文件进行读写,最后关闭文件
(作用:移除文件的ID)。
补充特性:标准IO的类型也分为两种:第一种:特殊文件 第二种:非特殊文件
第二步:程序运行的时候,特殊文件会自动打开(前三个,标准输入、标准输出、标准错误),
并自动分配文件流指针(FILE *fd)。非特殊文件,利用fopen()函数打开,系统自动分配一个文件流指针。
特殊文件的文件流指针含义:
第一个:标准输入 文件流指针:stdin;
第二个:标准输出 文件流指针:stdout
第三个:标准错误 文件流指针:stderr
2.2缓冲区
与文件IO的主要区别,就体现在缓冲区上。
对于大多数的标准IO函数,它的读写过程都是具有缓冲区的,因此标准IO的读写函数要满足一定的条件才能进行输出。
根据缓冲区的条件给标准IO分为两大类;
第一类:行缓存函数(需要满足的条件?)
第一个:程序顺序执行结束的时候;
第二个:文件被关闭的时候---调用close函数
第三个:行缓存被填满的时候(超过1K---1024)
第四个:读写函数里面包含了“\n”
第二类:全缓存函数(需要满足的条件?)
第一个:程序顺序执行结束的时候;
第二个:文件被关闭的时候---调用close函数
第三个:行缓存被填满的时候(超过1K---1024)
//验证缓冲区文件
#include <stdio.h>
int main()
{
char buff[]="sadjhfgdsklfgjw";
write(1,buff,sizeof(buff));
while(1);
}
//缓冲的条件
#include <stdio.h>
int main()
{
char buff[]="dasrfdghf5344fd5sdfs";
write(1,buff,sizeof(buff));
printf("%s\r\n",buff);
while(1);
}
现象:首先两个代码是相似的,都是通过显示后,加入while(1),但是write()函数它能够正常显示,但是printf()函数不能正常显示。
原因:首先write()函数是文件IO,不具备缓冲功能。然而,printf()函数,属于标准IO函数,具备缓存功能,所以缓冲功能函数正常执行需要满足条件。
第一个:行缓存和全缓存区别是什么?
全缓存:采用标准IO对缓存区进行操作。主要应用磁盘文件是利用全缓存的。
行缓存:主要是利用输入输出函数遇到换行符就进行行缓存。
三、标准IO的函数
头文件是:stdio.h
与文件IO对应的标准IO的5个函数:标准IO函数:fopen()、fclose()、fwrite()、fread()、fseek()
3.1fopen() 打开文件函数(可创建)
//标准IO的fopen()函数 指针函数 函数指针
原型:FILE *fopen(const char *pathname,const char* mode);
参数: const char *pathname 表示文件的路径(以字符串的形式进行表示)
const char* mode 表示打开文件的方式
打开方式进行解释:常用的r --->表示只读 O_RDONLY
W --->表示只写 O_WRONLY
w+ --->表示可读可写--可创建--可覆盖
r+ --->表示可读可写
a+ --->表示可读可写-可创建-可追加
返回值:成功: 返回文件流指针
失败: 返回NULL
功能:打开文件、可以创建文件
实例:实现可写-可创建-覆盖方式打开test.c
第一步:创建FILE *fp
第二步:fp=fopen("test.c","w+");
//实现文件的创建
#include <stdio.h>
#define FILENAME "a.c"
int main()
{
FILE *fp;
fp = fopen(FILENAME,"w+");
if(fp == NULL)
{
printf("fopen erro\r\n");
return -1;
}
printf("文件创建成功\r\n");
fclose(fp);
return 0;
}
3.2fclose() 关闭文件的函数
//标准关闭函数---fclose()
原型:int fclose(FILE *stream);
参数:FILE *stream --->表示文件流指针 (一般fopen()函数的返回值)
返回值:成功 返回0
失败 返回-1
功能:关闭一个文件流指针
3.3 fwrite() 写文件函数
//标准文件中写函数---fwrite() API
原型:size_t fwrite(const void* ptr,size_t size,size_t nmemb,FILE* stream);
参数:const void *ptr ---> 缓存空间的地址//指向要发送数据的位置
size_t size ---> 表示每块数据的长度(一般情况下设置为1)
size_t nmemb --->表示数据块的个数
FILE* stream --->表示文件流指针
返回值:返回实际写到的数据个数
功能:从ptr执行的缓存空间读取nmemb块的数据,每块数据的大小size,(注意:待写入数据的长度为nmemb*size单位字节)
然后将这些数据写入到对应的stream中。
应用实例:
功能:实现字符串显示到屏幕上。
char buf[]="hello linux";
fwrite(buf,1,sizeof(buf),stdout);
3.4 fread() 读文件函数
//标准IO函数读函数---fread()函数
原型:size_t fread(void *ptr,size_t size,size_t nmemb,FILE* stream);
参数:void *ptr --->表示缓存空间的地址 //保存这个地方
size_t size ---> 表示每块数据的长度(一般情况下设置为1)
size_t nmemb --->表示数据块的个数
FILE* stream --->表示文件流指针
返回值:返回实际读取到的数据长度
功能:从stream对应的文件中读取nmemb块数据,每块数据的大小为size,最后将读取到的内容写入到ptr指向的缓存空间里
应用实例:
功能:从键盘上获取数据
char buf[64];
fread(buf,1,sizeof(buf),stdin);
补充:可以利用stdin或者stdout进行标准输入和输出
3.5fseek() 调整文件读写位置
//标准文件中调整位置函数---fseek()调整文件一个读写位置函数
原型: int fseek(FILE* stream,long offset, int whence);
参数:FILE *stream --->表示文件流指针
long offset --->表示相对偏移量
int whence --->表示偏移基点---注意可以填写的参数有 SEEK_SET|SEEK_CUR|SEEK_END
返回值:成功 返回0
失败 返回-1
功能:重新调整文件的读写位置
注意:和之前用文件IO时候的lseek函数是不同的!,不能直接计算文件的大小,需要利用ftell()函数,返回当前读写位置值
//用fseek函数实现文件的大小的计算
#include <stdio.h>
int main()
{
char filename[] = "./a.c";
int fd_len;
FILE* fp;
fp = fopen(filename,"r");
fseek(fp,0,SEEK_END);
fd_len = ftell(fp);
printf("size:%d\r\n",fd_len);
fclose(fp);
return 0;
}
注意:
第一个问题:路径上的问题,需要还是用./ --》表示当前路径下
第二个问题:使用fopen函数的时候,第一个参数filename不能加引号。
四、标准IO里面的其他函数:
scanf()/printf() fscanf()/fprintf() getchar()/putchar() fgetc()/fputc()
gets()/puts() fgets()/fputs() fflush()/feof()
4.1fscanf()
//标准IO中的fscanf()函数
原型:int fscanf(FILE* stream,const char *format,str...);
参数:FILE* stream ----》表示文件流指针
const char *format -->和学习scanf的输入格式是一致的&
返回值:成功,返回有效输入字符的个数
失败,返回-1
功能:从文件中获取数据写入到对应的缓存空间里面。
注意:通过fscanf()函数获取字符串时候,空格将被视为分割对应的字符串。
4.2 fprintf()
//fprintf()
原型:int fpritf(FILE *stream,const char *format,...);
参数:FILE *stream --->文件流指针
const char *format ---》和学习printf的输出格式是一样的
返回值:成功,返回输出的字符个数。
失败,返回负数
功能:将缓存空间的内容写入到对应的文件中。
4.3 fgetc()
//fgetc()
原型:int fgetc(FILE *stream)
参数:FILE *stream ---》文件流指针
返回值:成功的话,返回读取到的字符
失败的话,返回EOF
功能:从文件中获取一个字符。
4.4 fputc()
//fputc() 标准IO中的一个输出函数
原型:int fputc(int c,FILE* stream);
参数:int c ---->表示待写入字符的个数。
FILE* stream ---->文件流指针
返回值:成功的时候,返回一个非负值。
功能:将指定的字符写入到对应的文件流中。
4.5 fgets()
//标准IO中的---fgets()函数
原型:char *fget(char *s,int size,FILE* stream);
参数:int size --->表示最多读取的字符个数
FILE* stream --->文件流指针
功能:fgets()从stream所指向的文件内部读取字符并存到s所指向的内存空间中。
4.6 fputs()
//标准IO中---fputs()函数
原型:int fputs(const char *s,FILE* stream);
返回值:如果成功的话返回写入的字符的个数。
失败的话返回EOF
功能:将参数s指向的字符串,写入到指定的文件中。
4.7 feof() 查看文件读写位置是否达到文件末尾
//feof() 查看文件读写位置是否达到了文件的末尾
原型:int feof(FILE* stream);
返回值: 如果读写位置达到了文件的末尾,则返回非0 if(a!=0)
如果读写位置没有达到文件的末尾,则返回0
功能:读写文件的位置是否达到文件的末尾。
应用实例:
while(feof(fp) == 0)
{
rd_len = fread(buf,1,sizeof(buf),fp);
fwrite(buf,1,rd_len,stdout);
}
4.8 fflush() 更新缓冲区函数
//fflush()函数---作用就是更新缓冲区
原型:int fflush(FILE* stream);
参数: FILE* stream ---->文件流指针
返回值:成功 返回0
失败的话返回NULL
功能:fflush()函数将缓存区的数据写回到stream文件中
五、标准IO和文件IO的区别
不同特带包含哪些?
第一个:使用的平台时不同的 文件IO适用于UNIX平台 标准IO适用于标准的C平台
第二个:操作对象不同 文件IO能够操作任何文件 标准IO主要用于操作普通文件
第三个:文件的ID不同 文件IO的文件描述符是int fd 标准IO里面用的文件流指针FILE *fp
第四个:缓冲区 文件IO没有缓冲区 标准IO是有缓冲区
第五个:读写效率不同 文件IO读写较低 标准IO读写效率较高
5.1函数库的概述
函数库是在程序运行的时候才生效。
函数库文件包括哪些? 第一个:静态库文件 第二个:动态库文件
通过静态库编写可执行文件,该文件具有运行所需要的所有数据,一般不需要安装,直接调用就可以使用。
XCOM。当相于串口助手
通过动态库编写可执行文件,该文件不具备独立运行的能力,需要安装才能运行。例如:QQ,浏览器。
5.2静态库的制作
第一步:建立一个静态库的源文件a.c ,编写需要的函数
第二步:将源文件编译生成目标文件a.c a.o
gcc a.c –o a.o
第三步:生成静态库文件
ar –cr libtest.a a.o
-c :代表创建的意思
-r :replace 代替的意思
第四步:建立一个源文件生成一个程序----加上静态库一起编译
gcc a.c –L –ltest –o main
5.3 动态库的制作
第一步:建立一个原文件a.c
第二步:将源文件编译成目标文件
gcc a.c –o a.o
第三步:生成动态库
gcc –fpic –shared a.c –o libadd.so
第四步:加上动态库一起编译生成可执行文件
gcc a.c libadd.so –o main
注意事项:
第五步:建议把动态库liabadd.so 放到/lib文件夹内 ----怎么做? sudo cp libadd.so /lib/
代码:
//利用标准IO函数,实现读写过程
#include <stdio.h>
#define FILENAME "a.c"
#define BUFFSIZE 256
int main()
{
FILE* fp;
char str1[BUFFSIZE] = "sdfgfghjgfdsadsaertrtyhfdsasdfdsfghf";
char str2[BUFFSIZE] = {0};
fp = fopen(FILENAME,"w+");
if(fp == NULL)
{
printf("fopen erro\r\n");
return -1;
}
fwrite(str1,1,BUFFSIZE,fp);
fseek(fp,0,SEEK_SET);
fread(str2,1,BUFFSIZE,fp);
printf("%s\r\n",str2);
fclose(fp);
return 0;
}
//2.实现通过fscanf()函数实现两次输出
#include <stdio.h>
#define FILENAME "a.c"
int main()
{
FILE* fp;
char str[128];
fp = fopen(FILENAME,"w+");
fprintf(fp,"hello world cyy");
fseek(fp,0,SEEK_SET);
fscanf(fp,"%s",str);
printf("str1:%s\r\n",str);
fscanf(fp,"%s",str);
printf("str2:%s\r\n",str);
fscanf(fp,"%s",str);
printf("str3:%s\r\n",str);
fclose(fp);
return 0;
}
//实现标准的输入和输出
#include <stdio.h>
int main()
{
FILE* fp;
char str[256];
printf("str:%p\r\n",str);
fgets(str,sizeof(str),stdin);
fputs(str,stdout);
}
//实现字符串的长度计算
#include <stdio.h>
#define FILENAME "a.c"
int main()
{
FILE* fp;
char str;
fp = fopen(FILENAME,"w+");
if(fp == NULL)
{
printf("fopen is failure\r\n");
return -1;
}
while(!feof(fp))
{
str = fgetc(fp);
fputc(str,stdout);
}
printf("size:%ld\r\n",ftell(fp));
fclose(fp);
return 0;
}