Linux C 标准(缓冲)IO编程

再要:

        哈喽!这里又是TheBlob 博客。本篇文章是IO编程基础的第一篇,主要讲述标准带缓冲IO编程。其中包括 IO编程概念、标准IO的缓冲、标准IO的输入输出函数以及函数使用的例子。希望能帮助大家!

目录 

概念

文件指针

打开和关闭文件

打开文件:

关闭文件:

标准IO的缓冲

全缓冲-----操作常规文件的时候

行缓冲-----操作标准输入和标准输出的时候

不带缓冲

格式化IO---输入与输出可以控制格式,printf(),scanf()

格式化输出函数

格式化输入

非格式化IO-----输入与输出没有格式,以字节流方式读写

一次一个一个字的IO输入

直接IO-----字节流

定位文件指针

获取文件指针的位移量


利用C库中的函数实现文件操作

文件操作的三部曲;

  • 打开文件
  • 读写文件
  • 关闭文件

定义:

        文件:一组相关数据的集合

        文件名:这个数据集合的名称

Linux中文件分类:

        (-)常规文件 ASCII码文件 二进制文件

        (d)目录

        (c)字符设备

          (b)块设备

          (p)有名管道

          (s)套接口

        (l)符号连接

概念

  • 不仅在UNIX系统,在很多操作系统上都实现了标准I/O库
  • 标准I/O库由ANSI C标准说明
  • 标准I/O库处理很多细节,如缓冲分配、以优化长度执行I/O等,这样使用户不必关心如何选择合适的块长度
  • 标准I/O在系统调用函数基础上构造的,它便于用户使用
  • 标准I/O库及其头文件stdio.h为底层I/O系统调用提供了一个通用的接口。

文件指针

        FILE指针:每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息,这些信息是保存在一个结构体类型的变量中,该结构体类型是由系统定义的,取名为FILE。

struct _IO_FILE;
typedef struct _IO_FILE FILE;
struct _IO_FILE {
		  int _flags;           /* High-order word is _IO_MAGIC; rest is flags. */
		#define _IO_file_flags _flags

		  /* The following pointers correspond to the C++ streambuf protocol. */
		  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
		  char* _IO_read_ptr;   /* Current read pointer */
		  char* _IO_read_end;   /* End of get area. */
		  char* _IO_read_base;  /* Start of putback+get area. */
		  char* _IO_write_base; /* Start of put area. */
		  char* _IO_write_ptr;  /* Current put pointer. */
		  char* _IO_write_end;  /* End of put area. */
		  char* _IO_buf_base;   /* Start of reserve area. */
		  char* _IO_buf_end;    /* End of reserve area. */
		  /* The following fields are used to support backing up and undo. */
		  char *_IO_save_base; /* Pointer to start of non-current get area. */
		  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
		  char *_IO_save_end; /* Pointer to end of non-current get area. */

		  struct _IO_marker *_markers;

		  struct _IO_FILE *_chain;

		  int _fileno;
		_IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

		#define __HAVE_COLUMN /* temporary */
		  /* 1+column number of pbase(); 0 is unknown. */
		  unsigned short _cur_column;
		  signed char _vtable_offset;
		  char _shortbuf[1];

		  /*  char* _save_gptr;  char* _save_egptr; */

		  _IO_lock_t *_lock;

	}

标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用FILE *来描述。

流(stream):

        定义:所有的I/O操作仅是简单的从程序移进或者移出,这种字节流,就称为流。

        分类:文本流/二进制流。

打开和关闭文件

打开文件:

#include<stdio.h>        头文件
FILE *fopen(const char *pathname, const char *mode);
//参数1 ---- 要打开的文件 
//参数2 ---- 打开的操作权限:
r 	   //只读,文件必须存在
r+     //读写,文件必须存在
w      //只写,文件不存在,则创建,文件存在,则把文件清空 
w+     //写读,文件不存在,则创建,文件存在,则把文件清空 
a 	   //只写, 文件不存在,则创建,文件存在,则在文件末尾追加
a+     //写读, 文件不存在,则创建,文件存在,则在文件末尾追加,如果是读,则从文件头开始读
//返回值 ---成功:文件指针,失败:NULL
例子:
int main(int argc,char **argv)
{
	FILE *fp;

	if(argc != 2){
		printf("Usage: %s <filename>\n",argv[0]);
		exit(1); //结束程序
	}

	//fp = fopen(argv[1],"r");
	//fp = fopen(argv[1],"r+");
	//fp = fopen(argv[1],"w");
	fp = fopen(argv[1],"a");
	if(fp == NULL){
		perror("fopen");
		exit(1);
	}
	return 0;
}

关闭文件:

int fclose(FILE *stream);
	//参数 ---- 文件指针 
	//返回值 ----成功:0,失败:-1
	
例如: 
int main(int argc,char **argv)
{
	FILE *fp;

	if(argc != 2){
		printf("Usage: %s <filename>\n",argv[0]);
		exit(1); //结束程序
	}

//打开文件
    fp = fopen(argv[1],"a");
	if(fp == NULL){
	    perror("fopen");
    	exit(1);
	}

//关闭文件
	fclose(fp); //刷新缓冲区,释放缓冲区
	
    return 0;
}

标准IO的缓冲

由于CPU的速度比硬盘快,因此为了提高效率。在程序和文件之间创建了一个缓存区,程序可以先将数据写到缓冲区中,然后在一点一点刷新到文件中。

全缓冲-----操作常规文件的时候

全缓冲刷新的条件:

  • 缓冲区满
  • 关闭文件
  • 强制刷新缓冲区
  • 程序正常结束

行缓冲-----操作标准输入和标准输出的时候

当运行一个程序,系统会自动默认打开三个设备文件:

                                      文件指针                设备

标准输入                            stdin                   键盘

标准输出                          stdout                   屏幕

标准错误输出                     stderr                 屏幕

输入与输出可以控制格式,例如:printf() 、 scanf()

行缓冲刷新的条件:

  • 缓冲区满
  • 关闭文件
  • 强制刷新缓冲区
  • 程序正常结束
  • 当行缓存区中遇到换行符(’\n‘)时
int main(int argc, char **argv)
{
    while(1){
        printf("hello world");
        usleep(100000);
    }//循环打印满了才显示在屏幕
    printf("hello world");
    while(1);//这一行一直不显示
    return 0;
}

不带缓冲

        没有缓冲区刷新的条件,直到往缓冲区写数据,会立即刷新。很多的人机交互界面要求不可全缓冲。标准出错决不会是全缓冲的。

例子:
int main(int argc,char **argv)
{
    printf("hello world");//通过标准输出打印,行缓存
    fprintf(stderr,"hello world")//通过标准错误打印,无缓冲
}

格式化IO---输入与输出可以控制格式,printf(),scanf()

格式化输出函数

int pritnf(const char *format,.....); //只能向标准输出写数据
int fprintf(FILE *stream,const char *format,......);//向指定的文件中写数据
例子;
int main(int argc,char **argv)
{
    FILE *fp;
    if(argc!=2){
        fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
        exit(1);                      
    }
    if((fp = fopen(argv[1],"w")) == NULL){
	perror("fopen");
	exit(1);
    }
    char buf[100];    
    while(1){//向文件中写数据
        bzero(buf,sizeof(100));
	scanf("%s",buf);
	fprintf(fp,"%s\n",buf);  //将buf输出的结果写到文件中
	fflush(fp);  //确保数据能够立即写到文件中,可以使用fflush()强制刷新
	}                  					
}

int sprintf(char *str, const char *format, ...);	//输出结果以字符串形式写到内存中
struct student{
	int sno;
	char name[20];
	float score;
};

int main(int argc,char **argv)
{
    int i;
    struct student st[3];
    char buf[5];
    //向内存中写数据
    for(i =0; i < 3; i++){//将键盘输入的结构体信息存入   结构体数组中
	printf("请输入学生信息:");
	scanf("%d%s%f",&st[i].sno,st[i].name,&st[i].score);
	sprintf(buf,"%d %s %.2f",st[i].sno,st[i].name,st[i].score);  //数组溢出
	printf("%s\n",buf);
    }//表面看起来没事但是会报警告,运行结束会段错误
    return 0;
}

 int snprintf(char *str, size_t size, const char *format, ...); 
 //输出结果以字符串形式写到内存中,同时限制写的字符数,防止溢出
 例如: 前面如上只是更该函数为 snprintf



snprintf(buf,5,"%d %s %.2f",st[i].sno,st[i].name,st[i].score);  //数组溢出

格式化输入

int scanf(const char *format, ...);  //从标准输入(键盘)获取数据
int fscanf(FILE *stream, const char *format, ...); //从指定文件中获取数据
例如: 
struct student{
    int sno;
    char name[20];
    float score;
};

int main(int argc,char **argv)
{
    FILE * fp;
    int i;
    struct student st[3];

    if(argc != 2){
	fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
	exit(1);
    }

    if((fp = fopen(argv[1],"r")) == NULL){
	perror("fopen");
	exit(1);
    }

//从文件中读出数据
    for(i =0; i < 3; i++){
	printf("请输入学生信息:");
	fscanf(fp,"%d%s%f",&st[i].sno,st[i].name,&st[i].score);
	printf("%d %s %.2f\n",st[i].sno,st[i].name,st[i].score);  //打印文件中的
       }
       return 0;
}

 int sscanf(const char *str, const char *format, ...); //从内存中获取数据
 struct student{
	int sno;
	char name[20];
	float score;
};

int main(int argc,char **argv)
{//应用就是将字符串以换形式输出     例如:时间 9:20分是字符串  用函数读取后再以整形打印

	struct student st;
	char buf[] = "1001 jack 87.56";

	sscanf(buf,"%d%s%f",&st.sno,st.name,&st.score);
	printf("%d %s %.2f\n",st.sno,st.name,st.score);  //将buf输出的结果写到文件中


    char buf[100];
    int h,m;

	printf("请输入时间:");
	scanf("%s",buf);
	sscanf(buf,"%d:%d",&h,&m);
	printf("%s为%d小时%d分钟\n",buf,h,m);

	int a;
	strcpy(buf,"123");
	sscanf(buf,"%d",&a);
	printf("a = %d\n",a);
     return 0;
}

非格式化IO-----输入与输出没有格式,以字节流方式读写

一次一个一个字的IO输入

1、输入
int fgetc(FILE *stream);   //(函数)从指定的文件中获取一次字符
int getc(FILE *stream);	  //(宏)从指定的文件中获取一次字符
int getchar(void);      //默认从标准输入(键盘)获取一次字符
		
例如: 
int main(int argc,char **argv)
{
	int a;
	char b;

	scanf("%d",&a);
	printf("a = %d\n",a);
	while(getchar() != '\n'); //清空输入缓冲区
	scanf("%c",&b);
	printf("b = %c\n",b);

	return 0;
}

2、输出
int fputc(int c, FILE *stream);  //(函数)向指定的文件中写一个字符
int putc(int c, FILE *stream);  //(宏)向指定的文件中写一个字符
int putchar(int c);       //向标准输出写一个字符
		
例如: 
int main(int argc,char **argv)
{
        FILE * rfp,*wfp;
        char ch;

	if(argc != 3){
		fprintf(stderr,"Usage: %s <src_filename> <target_filename>\n",argv[0]);
		exit(1);
	}

	if((rfp = fopen(argv[1],"r")) == NULL){
		perror("fopen");
		exit(1);
	}
	if((wfp = fopen(argv[2],"w")) == NULL){
		perror("fopen");
		exit(1);
	}

	//从一个文件中读数据,写到另一个文件中
	while((ch = fgetc(rfp)) != EOF){
		//printf("%c",ch);
		putchar(ch);
		fputc(ch,wfp);
	}

	fclose(rfp);
	fclose(wfp);
	return 0;
}

直接IO-----字节流

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);	
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
//参数1 ----- 内存地址 
//参数2 ----- 对象大小
//参数3 ----- 对象个数
//参数4 ----- 文件指针

例如: 
struct student{
	int sno;
	char name[20];
	float score;
};

int main(int argc,char **argv)
{
	FILE * fp;
	int i;
	struct student st[3];

	if(argc != 2){
		fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
		exit(1);
	}

	if((fp = fopen(argv[1],"w")) == NULL){
		perror("fopen");
		exit(1);
	}

	//向结构体中写数据
	for(i =0; i < 3; i++){
		printf("请输入学生信息:");
		scanf("%d%s%f",&st[i].sno,st[i].name,&st[i].score);
	}
	//直接iO,向文件中写三个结构体
	fwrite(st,sizeof(struct student),3,fp);

	return 0;
	}
 

例如:
struct student{
	int sno;
	char name[20];
	float score;
};

int main(int argc,char **argv)
{    //前面都一样,将文件的可执行改为   r 


    //直接iO,向文件中读三个结构体
	fread(st,sizeof(struct student),3,fp);

	//向结构体中写数据
	printf("学生信息:\n");
	for(i =0; i < 3; i++){
		printf("%d  %s  %.2f\n",st[i].sno,st[i].name,st[i].score);
	}

	return 0;
}
		
例如: 
int main(int argc,char **argv)
{
	//和前面将一个文件写去另一个文件一样

	//从一个文件中读数据,写到另一个文件中
	while(!feof(rfp) && !ferror(rfp)){
		bzero(buf,sizeof(buf));
		fread(buf,sizeof(char),sizeof(buf)-1,rfp);
		printf("%s",buf);
		fwrite(buf,sizeof(char),strlen(buf),wfp);
	}
 }

定位文件指针

获取文件指针的位移量

long ftell(FILE *stream);
//参数 ----- 文件指针
//返回值 ----成功:文件指针的位移量,失败:-1
	   
例如: 
int main(int argc,char **argv)
{
    FILE * fp;
    char ch;
    int i;

    if(argc != 2){
        fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
	exit(1);
    }

    if((fp = fopen(argv[1],"r")) == NULL){
	perror("fopen");
	exit(1);
    }
    for(i = 0; i < 7; i++){
	ch = fgetc(fp);
	printf("%c",ch);
	}
    printf("\n%ld\n",ftell(fp));//
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值