Linux C编程之标准I/O操作

目录

系列文章目录

一、流和FILE对象

二、基于流的I/O操作

1.对缓存的操作

2,流的打开与关闭

3,流的读写

一、流和FILE对象

        对于标准I/O库,对他们的操作是围绕流(stream)进行的,用标准I/O库打开或者创建一个文件时,已使一个流与一个文件相结合。当打开一个流时,标准I/O函数fopen返回一个指向FILE的指针,该对象通常是一个结构体,包含了I/O库为管理该流所需要的所有信息,包括文件描述符,指向流缓存的指针,缓存长度,当前缓存的字节数,出错标志等。指向FILE的指针被称为文件指针。

        基于流的I/O操作过程大致可以归纳如下:通过调用fopen函数打开,并且返回一个FILE指针,成功打开流之后,就可以调用库函数对其进行I/O操作,操作完成后,需要执行清空缓冲区,保存数据等操作,然后关闭流。        

        当使用流I/O时,标准输入,标准输出,标准出错这3个流在进程启动时是默认打开,在基于流的I/O中,通过预定义文件指针stdin,stdout,stderr来引用标准输入,标准输入和标准出错。

         基于流的操作最终会调用write和read函数进行I/O操作,为减少多次调用,流对象通常会提供缓冲区以减少调用次数。标准I/O提供了3种类型的缓存:

        全缓存:直到缓冲区被填满,才调用I/O函数。

        行缓存:直到遇到换行符'\n',才调用I/O函数,stdin,stdout。

        无缓存:数据立即读入或者输出,stderr。

二、基于流的I/O操作

1.对缓存的操作

   当调用fopen函数打开一个流时,就开辟了缓存区,缓存区参数有系统默认的值,实际使用时,可以根据自己的需求来进行更改:

        void setbuf(FILE* fp,char* buf);

        void setbuffer(FILE* fp,char* buf,size_t size);

         void setlinebuf(FILE* fp);

         void setvbuf(FILE* fp,char* buf,int mode,size_t size);

前3个函数没有返回值,setvbuf函数成功返回0,出错返回非0,fp是FILE结构体指针,应指向一个打开的流。

setbuf函数将缓冲区设置为全缓存或者无缓存,当buf指向一个真实的缓冲区地址时,表示全缓存,当buf指向NULL时,表示无缓存;

setbuffer同setbuf类似,size参数用来指定缓冲区大小;

setlinebuf专用于设置为行缓存;

setvbuf中参数mode用来指定缓冲区类型(_IOFBF(全缓存),_IOLBF(行缓存),_IONBF(无缓存))。

如下,修改stdin的缓存:

#include <stdio.h>
#include <stdlib.h>

#define SIZE 1024

int main()
{
char buf[SIZE];
//unbuffered  
if(setvbuf(stdin,buf,_IONBF,SIZE)!=0)  
{
		printf("some error\r\n");
		exit(1);
}
else
{
  printf("Set successful\r\n");
  printf("stdin is:\r\n");   
  // distinguish the types of buf
  if(stdin->_flags & _IONBF)
		  printf("unbuffered\r\n");
  else if(stdin->_flags & _IOLBF)
		  printf("line-buffered\r\n");
  else
		  printf("full-buffered\r\n");
  printf("buffer size is %ld\n",stdin->_IO_buf_end-stdin->_IO_buf_base);
}

  // full-buffered
if(setvbuf(stdin,buf,_IOFBF,SIZE)!=0)  
{
		printf("some error\r\n");
		exit(1);
}
else
{
  printf("Change successful\r\n");
  printf("stdin is:\r\n");   
  // distinguish the types of buf
  if(stdin->_flags & _IONBF)
		  printf("unbuffered\r\n");
  else if(stdin->_flags & _IOLBF)
		  printf("line-buffered\r\n");
  else
		  printf("full-buffered\r\n");

  printf("buffer size is %ld\n",stdin->_IO_buf_end-stdin->_IO_buf_base);

}
return 0;
}


执行结果如下:

缓存的清洗;

int fflush(FILE *fp) ; 

该函数用于将缓冲区尚未写入的文件强制性的保存在文件中,调用成功返回0,失败返回EOF。

2,流的打开与关闭

流的打开:

对一个流进行操作之前,首先要打开流,即建立某个流与特定文件和设备之间的关联,打开流的函数如下:

FILE * fopen(const char* pathname,const char* type);

FILE * freopen(const char* pathname,const char* type,FILE *fp);

FILE* fdopen(int fd,const char* type);

fopen函数打开路径为pathname的文件;

freopen函数在一个特定的流上,打开指定文件,若已经打开,则先关闭,一般用于将一个指定文件打开为一个预定义的流:标准输入,标准输出,标准出错;

fdopen取一个现成的文件描述符,并使得一个标准I/O流与该文件描述符相结合。

type参数指定了对I/O的读写方式,常见的有:r,w,w+,a,a+,rb等等,a表示追加写,b表示以二进制文件打开。

流的关闭:

int fclose(FILE *fp);成功返回0,否则返回-1。

fclose函数在关闭文件时,会将存在于缓冲区未来得及写进磁盘的内容写进磁盘。

例如,打开和关闭一个流:stream.c

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
  FILE *fp;   //creat a ptr pointed to file stream
  int fd;
  //using fopen to open by stream
  if((fp=fopen("/home/huahua/Linux_C/file/stream.txt","r+"))==NULL)
  {
    printf("fail to open1\r\n");
	exit(1);
  }
  fprintf(fp,"This is Linux C!\n");
  fclose(fp);
   //打开文件,获取文件描述符
  if((fd=open("/home/huahua/Linux_C/file/stream.txt",O_RDWR))==-1)
  {
    printf("fail to open2\r\n");
	exit(1);
  }
  //using fdopen to open by stream 
  if((fp=fdopen(fd,"a+"))==NULL)
  {
     printf("fail to open stream");
	 exit(1);
  }
  fprintf(fp,"I am doing a Linux program!\n");
 // printf("debug------1\n");
  fclose(fp);   //cloae this stream

return 0;
}

3,流的读写

一旦打开了流,可在四种不同类型的I/O中进行选择来进行读写操作:

基于字符的I/O: 

用来处理单个字符。

读入字符:  int getc(FILE*fp);

                     int fgetc(FILE* fp);

                     int getchar(void);

成功返回读取的字符,到达文件尾或者出错返回EOF,fp表示要读入字符的文件,getchar用于标准读入,相当于fget(stdin);区分发生错误或者到达文件尾使用ferror和feof。

输出字符:  int putc(int c,FILE *fp);

                    int fputc(int c,FILE *fp);

                    int putchar(int c);

成功返回c,出错返回EOF,putchar用于标准输出;

基于行的I/O:

当内容遇到'\n'时,将流中'\n'之前的内容送到缓冲区。

行的读入:

char * fgets(char* buf,int n,FILE *fp);

char * gets(char *buf);

成功返回缓冲区的首地址,到达文件尾或者出错返回NULL,buf表示读入串的缓冲区,n表示读入字符的个数,n不大于缓冲区的长度,gets函数用于标准输入。

行的输出:

int fputs(const char *buf,FILE *restrict fp);

int puts(const char *str);

成功返回输出的字节数,失败返回-1,buf 表示存放输出内容的缓冲区,fp表示要输出的文件。

直接I/O:

size_t  fread(void * ptr,size_t size ,size_t nmemb,FILE *fp);

size_t  fwrite(const void * ptr,size_t size ,size_t nmemb,FILE *fp);

fread用于输出操作,ptr是指向读取数据缓冲区的指针,size是读取对象的大小,nmemb是读取对象的个数;

fwrite用于输入操作,参数类似fread。

均返回读或写得对象数。

如下,实现文件复制操作:

#include <stdio.h>
#include <stdlib.h>

#define Src_File "/home/huahua/Linux_C/file/scr.txt"
#define Des_File "/home/huahua/Linux_C/file/des.txt"

int main()
{ 
FILE *fp1,*fp2;
char buf[1024];
int n;
   if((fp1=fopen(Src_File,"rb"))==NULL)    
   {
         printf("scr file error\n");
		 exit(1);
   }
   if((fp2=fopen(Des_File,"wb"))==NULL)
   {
  printf("des file error\n");
		 exit(1);
   }
   while((n=fread(buf,sizeof(char),1024,fp1))>0)
       {
           if(fwrite(buf,sizeof(char),n,fp2)==-1)
		   {
				   printf("fail to write\n");
				   exit(1);
		   }
		   if(n==-1)
		   {
              printf("fail to read\n");
			  exit(1);
		   }

	   }
    fclose(fp1);
	fclose(fp2);
    return 0;
}

运行结果scr.txt文件内容成功复制到des.tx中。 

格式化I/O:

int printf(const char* format,...);

int fprintf(FILE *fp,const char *format);

成功返回输出的字符数,出错返回负值,printf用于标准输i

int scanf(const char* format,...);

int fscanf(FILE *fp,const char* format,...);

成功返回输入项数,出错或者到结尾返回EOF,scanf从标准流输入,fsanf从指定流输入。

如下程序,实现输入输出:

#include <stdio.h>

#define File_path "/home/huahua/Linux_C/file/scr.txt"
int main()
{
  FILE *fp;
  char buf[]="What a hot day!!!\n";
  char buf2[80];
  fp=fopen(File_path,"w");
  fprintf(fp,"%s",buf);
  fprintf(fp,"\n");
  fclose(fp);
   fp=fopen(File_path,"r");
  fscanf(fp,"%s",buf2);
  fclose(fp);
  printf("%s\n",buf2);
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值