标准IO
标准IO-介绍
我们知道IO操作分为系统自带的文件IO与库函数的标准IO,文件IO是非缓冲的文件系统
(低级磁盘IO)而标准IO是带有缓冲文件系统的(高级磁盘IO)
标准IO库处理很多细节,比如缓存的分配,以优化长度执行IO等
而标准IO是在系统调用的函数基础上构造的,它为了提高用户的使用,从而为底层IO提供了一个通用接口
如题所示普通的文件IO是直接与内核交互,而标准IO则是先通过库函数整合之后再与系统交互,加快了交互过程中的资源交换等等。比较高效属于高级IO00
标准IO->流和FILE对象
文件指针:FILE 指针 和文件IO中的fd一样是为了区分不同文件的表示符号,不过这个符号较为特殊不单单是一个整数,而是一个指针,指针指向一个结构体结构体中有文件指针的位子,文件标志,文件缓冲区状况,文件大小等等数据,用来抽象的描述一个流的基本参数
标准IO中的文件缓存系统
在标准IO中有着一个特殊的文件缓存系统,其目的是为了尽量减少使用read/write的调用
定义:系统自动在内存中为每一个正在使用的文件开辟一个缓冲区,从内存向磁盘输出数据必须先送到内存缓冲区,装满缓冲区或者接收到固定的字符时 再一起送到磁盘中,分别分为全缓存,行缓存
和,不带缓存。
全缓存:当填满IO缓存后在写进内存,或者用于fflush函数来刷新缓存才进入内存
行缓存:当填满后或遇到‘\n’或者用fflush函数刷新后进行IO操作
无缓存:没有缓存例如stderr
使用setbuf()和setvbuf可以更改缓存内型
系统自定义了3个流,他们可以自动的位进程所使用的。
(标准输入, 0, STDIN_FILENO,stdin)
(标准输出,1,STDOUT_FILEND,stdout)
(标准错误输出,2,STDERR_FILENO,stderr)
一.打开流fopen()
fopen().2个参数,返回值是成功返回FILE * 文件流指针,失败返回NULL
fopen(const char *path,char mode)
@path :文件的路径 文件IO一样是char * 类型 .
@char mode 字符串类型需要加上双引号,与其不同的是只有一个参数
打开标准IO流mode参数如下
r或rb :打开只读文件,文件必须存在
r+或rb+ :打开可读写文件,文件必须存在
w或wb :打开只写文件,若文件存在则文件长度清0,即擦拭文件,文件不存在就创建
w+或wb+:打开可读写文件,若文件存在则文件长度清0,即擦拭文件,文件不存在就创建文件
a或ab 以附加的方式打开只写文件,若文件不存在,则传立文件,写入的时候以追加方式写入即不会擦拭会紧接着写文件
a+或者ab+:已附加方式打开读写文件,若文件不存在则创立文件,写入的时候追加方式,即不会擦拭会紧接着写文件
(个人总结:r读w写+代表读和写,w擦拭a追加,加b代表二进制)
eg:
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main(int argc,const *argv[])
{
FILE* fp;
if((fp = fopen("test","w+")==NULL)
{
fprintf(stdeer,"fopen failed : %s \n",strerror(errno));
//一个标准文件显示,第一个参数是输出到哪(文件),第二个是输出什么内容,非常实用
retuen -1;
}
fclose(fp);
return 0;
}
二.标准IO的读写流
1.1 标准IO的读写函数
标准IO有很多的读写函数各有各的作用于用法接下来我列出参数与代码帮助大家理解
fgetc:读一个字符
fputc:写一个字符
函数模板:
int fgetc (FILEstream)
int fputc (FOLEstream)
这两个函数都是用于读或写一个字符。成功则为下一个字符,若失败或者到达文件末尾处则返回EOF,要注意的是这里读完也会返回EOF,所以我们要用到feof()和ferror()两个函数来做以区分,一般是feof可以为1 ferror不能为1 表示已读完但不出错
利用这两个函数我们可以做一个小程序可以实现lux中的cat 指令用于查看某个文件的内容并将它打到屏幕上
代码如下:
#include<stdio.h>
#define MAX 128;
int main(int argc, const char *argv[])
{
FILE *fp;
char read_c;
char put_c;
fp=fopen(argv[1],"r");
if (fp==NULL)
{
printf("the open is filed\n");
return -1;
}
while(1)
{
read_c = fgetc(fp);
if(feof(fp)==1&&ferror(fp)==0)
{
printf("the read is gone\n");
break;
}
put_c= fputc(read_c,stdout);
}
return 0;
}
这个函数与linux中的几乎一样哟小伙伴们可以将它放在bin目录下之后就可以直接运用了
三.fgets 与fputs
刚才介绍了读写一个的的标准IO接下来就是读写一行的IO
char * fgets(char s,int size ,FILEstream)
int fputs (const char s,FILEstream)
这两个函数当然是读一串字符,与标准IO一样有着读哪里 读多少,读什么的规则,不懂得可以参考上一篇的文件IO
而做与对比我这里给出一个和上篇一样的cp函数供大家参看~~
#include<stdio.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
FILE * fp;
char read_buff[15] = {'0'};
char put_buff[15] = {"hello ypf"};
int put_size;
char * fget_read;
fp=fopen(argv[1],"w+");
if (fopen==NULL)
{
printf("the open is flied\n");
return -1;
}
put_size = fputs(put_buff,fp);
if (!put_size)
{
printf("the put is flied\n");
return -2;
}
rewind(fp);
fget_read = fgets(read_buff,sizeof(put_buff),fp);
if (fget_read == NULL)
{
printf("the read is filed");
return -3 ;/* code */
}
printf("the read is %s\n",fget_read);
return 0;
}
四.文件目录得操作
在文件目录IO中我们操作的都是文件目录IO包括打开目录 读取目录等 像我们用过的 mkdir 就是linux下的标准目录
首先我们还是要用到opendir 读目录 非常简单的一个函数
DIR * opendir (char *);
打开目录返回的是一个目录流指针,而里面参数则是你要得到的文件目录路径
打开后就是
读函数读取一个目录 相当于就是读取目录里有什么文件,问大家能id和文件大小等一些参数与ls-l一样而他读写的参数放入一个结构体中
struct dirent *dir ;
dir = readdir(dp)
dp就是打开后的目录流指针
读写后可以通过dir->d_ino,dir->d_name等来显示文件具体大家可以用man命令来查看
五。实现小程序单机上的文件上传和下载
此项目完成了在单机上的下载与上传,首先输入一串文件目录地址,得出服务器的位置,之后选择上传或者下载 。收件会弹出当前服务器中的内容,之后输入你要下载或者上传的文件名字,完成后根据提示可以在当前文件夹,或服务器中找到你下载的文件~
实现单机的下载与上传。
代码如下:
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
int up(DIR *dp,struct dirent *dir,char *server)
{ int open_fd1;
int open_fd2;
int read_fd;
int write_fd;
char read_buf[100]={0};
char write_buf[100]={0};
char file_name[100] = {0};
dir = readdir(dp);//读取目录
if(dir==NULL)
{
printf("the readdir is fail\n");
}
else{
printf("indoe = %ld\t file_name = %s\n",dir->d_ino,dir->d_name);
}
printf("\npuease input you want up file_name\t\n");
scanf("%s",file_name);
open_fd2 = open(file_name,O_CREAT|O_RDWR,0777);
if(open_fd2 <0)
{
printf("the open2 is falid\n");
return -2;
}
open_fd1 = open(strcat(strcat(server,"/"),file_name),O_CREAT|O_RDWR,0777);
if(open_fd1 <0)
{
printf("the open1 is fail\n");
return -1;
}
//打开双方文件
while(1)
{
read_fd = read(open_fd2,read_buf,sizeof(read_buf));
if(read_fd ==0)
{
printf("the read is down\n");
}
write_fd =write(open_fd1,read_buf,sizeof(read_buf));
}
write_fd = write(open_fd1,read_buf,sizeof(read_buf));
printf("----------------------------------\n");
printf("the down is ok\n\n");
return 0;
}
//读写上传
//上传文件函数
int down(DIR *dp,struct dirent *dir,char *server)
{ int open_fd1;
int open_fd2;
int read_fd;
int write_fd;
char read_buf[100]={0};
char write_buf[100]={0};
char file_name[100] = {0};
dir = readdir(dp);
if(dir==NULL)
{
printf("the readdir is fail\n");
}
else{
printf("indoe = %ld\t file_name = %s\n",dir->d_ino,dir->d_name);
}
printf("\npuease input you want down file_name\t\n");
scanf("%s",file_name);
open_fd1 = open(strcat(strcat(server,"/"),file_name),O_RDWR,0777);
if(open_fd1 <0)
{
printf("the open1 is fail\n");
return -1;
}
open_fd2 = open(file_name,O_CREAT|O_RDWR,0777);
if(open_fd2 <0)
{
printf("the open2 is falid\n");
return -2;
}
while(1)
{
read_fd = read(open_fd1,read_buf,sizeof(read_buf));
if(read_fd ==0)
{
printf("the read is down\n");
break;
}
write_fd =write(open_fd2,read_buf,sizeof(read_buf));
}
write_fd = write(open_fd2,read_buf,sizeof(read_buf));
printf("----------------------------------\n");
printf("the down is ok\n\n");
return 0;
}
//下载函数
int main(int argc, const char *argv[])
{
int ok;
DIR *dp;
int fd;
int ret;
struct dirent *dir;
char server[128] = {0};
start:
printf("plese input server PATH and DIRect name \n");
scanf("%s",server);
dp = opendir(server);
if (dp==NULL)
{
printf("the dir open is falid\n");
goto start;
}else printf("the dir openis ok \n");
printf("down or up \n");
printf("if you want to down input 1 else 2\n");
scanf("%d",&ok);
if(ok==1)
{
ret = down(dp,dir,server);
if(ret<0)
{
printf("erro\n\n");
}else printf("is good\n");
closedir(dp);
}
if(ok==2)
{
ret = up(dp,dir,server);
if(ret<0)
{printf("error\n");
}else printf("is good\n");
closedir(dp);
}
return 0;
}
//谢谢观看
六.总结:
由此IO这一步部分的复习结束,IO这一步份逻辑并不多大多是函数之间的装换。和标准与文件IO的各有不同。有很多细节的东西就没卸载博客上面如果有任何不懂或者代码出现问题看不懂的请况 可以随意联系作者
作者联系方式
QQ1339781385
微信:y1339781385
学习嵌入式,互相交流,各种软件交互,教学视频,资料,软件破解都可联系本作者,作者都将无条件帮助。
下一阶段
进程间的通信