Linux应用层开发(一)标准I/O

只要操作系统中安装了C库就可以调用标准I/O的函数
标准I/O可以减少系统调用的次数,在执行系统调用的时候系统必须从用户态切换到内核态,处理相应请求再返回用户态,频繁切换会增加系统的开销,标准I/O使用时再用户空间创建了一个缓存区,读写时,先操作缓冲区,在合适的时机再通过系统调用访问实际的文件,从而减少了使用系统调用的此时。

注意:因为我们是以文件为例,所以我们把后面设计到的流都称为文件

打开文件:FILE* fopen(const char *path,const char *mode)

头文件:#include<stdio.h>
返回值:成功:返回一个文件类型的指针,失败:返回NULL
第一个参数:一个指向字符串常量的指针,或者说是一个字符串
第二个参数:文件打开的方式,如a,b等详细描述见下表,也是一个字符串

r或rb只读,文件必须存在
r+或r+b可读写,文件必须存在
w或wb只写,清空原有内容,文件不存在就建立
w+或w+b可读写,清空原文件,文件不存在就建立
a或ab只写,新写的数据加到文件末尾,文件不存在就建立
a+或a+b可读写,新写的数据加到文件末尾,文件不存在就建立

关闭文件:int fclose(FILE *Stream)

头文件:#include<stdio.h>
返回值:成功:返回0,失败返回:EOF(-1)
参数:一个文件类型的指针

实例:

#include<stdio.h>
int main()
{
	FILE *fp;
	if((fp=fopen("路径/文件名""r"))==NULL)
	{
		perror("open fail");//打印错误信息
		return -1;
	}
	fclose(fp);
} 

按字节输入:int getc(FILE *Stream)

按字节输入:int fgetc(FILE *Stream)

头文件:#include<stdio.h>
返回值:成功:读取的字符,失败:返回EOF(-1)
参数:文件类型的指针

例子:

#include<stdio.h>
int main()
{
		FILE *fp;
	if((fp=fopen("路径/文件名""r"))==NULL)
	{
		perror("open fail");//打印错误信息
		return -1;

	}
	char ch=fgetc(fp);
	printf("%c\n",ch);//查看获取的字符
	fclose(fp);

}

按字节输出:int putc(int c,FILE *Stream)

按字节输出:int fputc(int c,FILE *Stream)

头文件:#include<stdio.h>
返回值:成功:输出的字符,失败:返回EOF(-1)
参数:文件类型的指针

例子:

#include<stdio.h>
int main()
{
		FILE *fp;
	if((fp=fopen("路径/文件名""r"))==NULL)
	{
		perror("open fail");//打印错误信息
		return -1;

	}
	char ch='1';
	fputc(ch,fp);
	fclose(fp);
}

按行输入char* fgets(char *s,int size,FILE* Stream)

头文件:#include<stdio.h>
返回值::成功:返回s,失败或到达文件末尾:返回:NULL;
第一个参数:存放输入字符串缓冲区的首地址
第二个参数:输入字符串的大小(缓冲区大小应该-1>=size,否则容易出问题)
第三个参数:一个指向文件的指针

例子:

#include<stdio.h>
#define SIZE 5
int main()
{
		FILE *fp;
	if((fp=fopen("路径/文件名""r"))==NULL)
	{
		perror("open fail");//打印错误信息
		return -1;

	}
	char ch[SIZE];
	fgets(ch,SIZE,fp);
	fclose(fp);
}

按行输出:int fputs(const char *s,FILE* Stream)

头文件:#include<stdio.h>
返回值::成功:返回s,失败:返回:NULL;
第一个参数:存放输出字符串的首地址
第二个参数:一个指向文件的指针

例子:
例子:

#include<stdio.h>
#define SIZE 5
int main()
{
		FILE *fp;
	if((fp=fopen("路径/文件名""r"))==NULL)
	{
		perror("open fail");//打印错误信息
		return -1;
	}
	char ch[10]="hello";
	fputs(ch,fp);
	fclose(fp);
}

在文件中定位到指定位置读写:int fseek(FILE *stream,long offset,int whence);

头文件:#include<stdio.h>
返回值:成功返回0,失败返回EOF(-1);
第一个参数:一个指向文件的指针
第二个参数:相对于基准位置的偏移量
第三个参数:基准值

whence基准值
SEEK_SET代表文件起始位置
SEEK_END代表文件结束位置
SEEK_CUR代表文件当前读写位置

返回当前文件的位置:long ftell(FILE *stream);

头文件:#include<stdio.h>
返回值:成功:返回当前读写位置,失败:返回EOD(-1)
参数:一个指向文件的指针

以指定大小为单位读文件:

size_t fread(void *ptr,size_t size,size_t nmemb,FILE* Stream)

头文件:#include<stdio.h>
返回值:成功返回实际读取到的记录个数; 失败:返回EOF(-1)
第一个参数:存放读入记录缓冲区的首地址
第二个参数:每次读取的记录的大小
第三个参数:读取的记录数
第四个参数:一个指向文件的指针

注意事项:一般应该满足:缓冲区的大小=第二个参数*第三个参数

以指定大小为单位写文件:

size_t fwrite(void *ptr,size_t size,size_t nmemb,FILE* Stream)

头文件:#include<stdio.h>
返回值:成功返回实际读取到的记录个数; 失败:返回EOF(-1)
第一个参数:存放写入记录缓冲区的首地址
第二个参数:每次写入的记录的大小
第三个参数:写入的记录数
第四个参数:一个指向文件的指针

下面给出一个文件复制的例子:

#include<stdio.h>
#define N 1024 //缓冲区的大小
#define n 1//预设记录数
#define m 1024//每个记录的大小
int file_size(const char* filename);
int copy_file(const char* s_f_name,const char* d_f_name);
int main()
{

copy_file("路径/源文件名","路径/目标文件名")

}

int file_size(const char* filename)
{
	FILE *fp;
	int SIZE=0;
	
	if(NULL==(fp=fopen(filename,"r"))
	{
		perror("open fail");
		return -1;
	}
	if(EOF==(fseek(fp,0.SEEK_END))//将读写位置定位到最末尾
	{
		perror("fseek fail");
		return -1;
	}
	if(EOF!=SIZE=ftell(fp))//返回在当前文件中的位置
	{
		flcose(fp);
		return SIZE;
	}
	else
	{
		flcose(fp);
		return -1;
	}

}
int copy_file(const char* s_f_name,const char* d_f_name)
{

	FILE *fps,*fpd;
	char buf[N];
	long long S_SIZE=0;
	int M=0;//实际的记录数
	if(EOF==(S_SIZE=file_size(s_f_name)))
	{
		perror("file_size fail");
		return -1;
	} 
	if(NULL==(fps=fopen(filename,"r"))
	{
		perror("openfile");
	}
	if(NULL==(fps=fopen(filename,"w"))
	{
		perror("openfile");
	}
	if(S_SIZE>1024)
	{
	while(M=fread(buf,m,n,fps))//返回值M是实际读取到的记录数,当没能读取到记录数的时候退出循环
	{						//这里的m*n应该小于等于缓冲区的大小,否则会出现段错误
		fwrite(buf,m,M,fpd);//这里的M应该设计为实际的记录数
	}						//fwrite和fread每次读取记录应该相同大小,所以我都设置为m
	}
	else
	{
		while(M=fread(buf,S_SIZE,n,fps))
	{
		fwrite(buf,S_SIZE,M,fpd);
	}
	}
}

格式化输入int sscanf(char* buf,const char *format,...)

头文件:#include<stdio.h>
返回值:成功:返回输出字符数(从buf取出的字符数)。失败:返回EOF(-1)
第一个参数:作为输入的缓存区
第二个参数:输入格式
第三个参数及其以后的参数:用来接收转化后的字符

例子:

#include<stdio.h>
int main()
{
	char buf1[10]="1234 123,23;
	char buf2[20];
	sscanf(buf1,"%d %d,%d",buf2,&buf2[1],&buf2[2]);
	int i=0;
	while(i<3)
	{
		printf("%d\n",buf2[i]);
		
	}
}

格式化输入:int fscanf(FILE* buf,const char *format,...)

头文件:#include<stdio.h>
返回值:成功:返回输出字符数(从buf取出的字符数)。失败:返回EOF(-1)
第一个参数:作为输入的缓存区
第二个参数:输入格式
第三个参数及其以后的参数:用来接收转化后的字符

#include<stdio.h>
int main()
{
	FILE *fp;
	if(NULL==(fp=fopen("文件路径/文件名","r")))
	{
		perror("oepn fail");
		return -1;
	}
	char buf2[20];
	sscanf(fp,"%d %d,%d",buf2,&buf2[1],&buf2[2]);
	int i=0;
	while(i<3)
	{
		printf("%d\n",buf[i]);
		
	}
	fclose(fp);
}

格式化输出:int sprintf(char *buf,const char* format,...)

头文件:#include<stdio.h>
返回值:成功:返回输出字符数(输出到第1个参数中字符数)。失败:返回EOF(-1)
第一个参数:作为输出的缓存区
第二个参数:输出格式
第三个参数及其以后的参数:存放需要转化的数据

#include<stdio.h>
int main()
{
	char buf1[10]={1,23}char buf2[20];
	sprintf(buf2,"%d%d%d",buf1[0],&buf1[1],&buf1[2]);
	int i=0;
	while(i<3)
	{
		printf("%c\n",buf1[i]);
		
	}
}

打印结果:1
		 2
		 3

格式化输出:int fprintf(FILE *buf,const char* format,...)

头文件:#include<stdio.h>
返回值:成功:返回输出字符数(输出到第1个参数中字符数)。失败:返回EOF(-1)
第一个参数:作为输出的缓存区
第二个参数:输出格式,第三个参数是什么类型,第二个参数就要什么类型
第三个参数及其以后的参数:存放需要转化的数据

#include<stdio.h>
int main()
{
	FILE *fp;
	if(NULL==(fp=fopen("文件路径/文件名","a")))
	{
		perror("oepn fail");
		return -1;
	}
	char buf1[10]={1,23}sprintf(fp,"%d%d%d",buf1[0],&buf1[1],&buf1[2]);
	
}

执行成功后,指定的文件会在末尾添加buf1[0],buf1[1],buf1[2]中存放的数据。

一个显示时间的案例

#includ<stdio.h>
#include<unistd.h>//sleep的头文件
#include<time.h>//time相关头文件
int main(int argc,char *argv[])
{
		FILE *fp;
		time_t t;
	if(argc<2)
	{
		printf("usage:%s<filename>",argv[0]);
	}
	if(NULL==(fp=fopen(argv[1],"w")))
	{
		perror("oepn fail");
		return -1;
	}
	while(1)
	{
		time(&t);
		fprintf(fp,"%s",ctime(&t))//注意默认是按行缓存的
		fflush(fp);//强制清空fp流的缓冲区
		//setbuf(fp,NULL);//fp流不设置缓冲区
		sleep(1);
	}

}

如果不设置缓冲区,缓冲区满了才会将数据放入我们指定的文件;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值