标准IO 流和流指针 缓存区分类 标准io操作函数

【1】I/O

i:input 输入 从文件中输入内容到内存中
o:output 输出 从内存中将内容写道文件中
内存:掉电数据会丢失 RAM
实际磁盘内存(物理内存空间):掉电数据不会丢失 ROM
linux中文件类型七种:bcd-lsp
b: 块设备
c: 字符设备
d:目录文件
-:普通文件
l : 链接文件
s:套接字文件
p:管道文件

【2】标准IO

标准IO是指在C库中提供的一组专门用于输入输出的函数

标准I/O由ANSI C标准定义

不仅在UNIX系统,在很多操作系统上都实现了标准I/O

标准I/O通过缓冲机制减少系统调用次数,实现更高效率
标准I/O库的所有操作都是围绕流(stream)来进行的,
在标准I/O中,流用FILE *来描述。
标准IO默认打开了三个流:stdin、stdout、stderr
标准输入、标准输出、标准出错

补充:系统调用(文件IO)

linux内核:
 应用层:  app   shell命令
               |  |
			   |  shell解析器  bash  sh csh ksh
			   |  |
			   |  |
	           | c库
               |  |
   -----------系统调用----------
   
   内核
   -----------------------------
   硬件

系统调用:是内核向上提供的函数接口,不同的操作系统的内核,向上提供的函数接口是不同的。
  (文件IO) ,没有缓冲机制。 

c库:在系统调用前做了一个二次封装,是间接的进行了系统调用。(标准IO)
c库可以在不同的操作系统上使用。
  char buf[1024];//是在使用读文件或写文件的时候开辟
  //特点,一次性读满后,实际的读函数用多少,从这个缓存区中拿多少,直到缓存区的内容
  //被读拿完,再次遇到读函数,才会进行第二次系统调用读满缓存区。
   fread(8byte)--》c库  实际要用8byte
      一次性读满buf   
  {
       if(是linux)
	      read(buf=1024);
	   else if(是 windows)
	      Read(buf=1024);
	   else if( 是 mac)
	      _read();

 }

【3】流(stream)和流指针(FILE *)

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

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

【4】缓存区的分类

1.全缓存:基于文件
 刷新条件:
    1)缓存满刷新
    2)fflush强制刷新
    3)正常结束(main:return 0;)
    4)exit退出进程函数		
 
2.行缓存:stdin、stdout
   刷新条件:
    1)缓存满刷新
    2)‘\n’刷新
    3)fflush强制刷新
    4)正常结束(main:return 0;)
    5)exit退出进程函数	
       exit(-1);	

特殊情况:当遇到scanf等阻塞等待输入的函数,输出缓存区会刷新。 		   
	
3.不缓存:stderr

char* _IO_buf_base; //缓存去的起始地址
char* _IO_buf_end; // 缓存区的截止地址

缓存区的截止地址-起始地址=缓存区大小

【5】标准io操作函数

1.fopen  /  fclose    打开/关闭文件
2.fgetc  /  fputc     一个字符的io
3.fgets /  fputs      一行的io 
4.fread  /  fwrite    直接io


man手册
man man  查看man手册功能

   1   Executable programs or shell commands   查看shell命令
   2   System calls (functions provided by the kernel)    查看内核向上提供的函数接口(系统调用函数)
   3   Library calls (functions within program libraries)  c库函数


1.fopen
  FILE *fopen(const char *path, const char *mode);
  功能:打开指定路径下的文件
  参数:
     path:文件的路径
	 mode:打开文件的方式
	   r:只读、文件指针定位到文件的开头
	   r+:可读可写、文件指针定位到文件的开头
	   w: 只写、文件存在清空、不存在创建、文件指针定位到文件开头
	   w+:可读可写、文件存在清空、不存在创建、文件指针定位到文件开头
	   a:追加(只写)、文件存在追加、不存在创建。追加到文件结尾
	   a+:追加(可读可写),写在结尾,读在文件开头。文件不存在创建。
	    
  返回值:
     成功:文件流指针
	 失败:NULL 更新errno

	   //一个文件可以被打开多次,每次返回的流指针都是不同的。

2.perror
 void perror(const char *s);
 功能:根据errno值打印对应的错误信息 
 参数:s:提示的字符串
 返回值:无

   #include <string.h>
   char *strerror(int errnum);
   功能:根据errno值打印对应的错误信息 
   参数:errnum--》errno值    #include <errno.h>
   返回值:
       成功:错误信息字符串的首地址
	   失败:NULL


3.fclose
 int fclose(FILE *stream);
 功能:关闭文件
 
 返回值:成功0 失败EOF(-1)

练习:验证一个进程中最多能打开多少个文件? 1024
一个进程中打开的文件个数是固定的,属于有限资源,用完后需要释放。

4.fgetc
 int fgetc(FILE *stream);
 功能:从指定的文件中读取一个字符
 参数:
    stream 文件流指针
 返回值:
     成功:读到字符的ascii值
	 失败或读到文件结尾:EOF 

5.fputc
 int fputc(int  c, FILE *stream);
 功能:向指定的文件中写入一个字符
 参数:
    c:要写入字符
	stream:文件流指针
返回值:
    成功:字符的ascii值
	 失败:EOF 

6.fgets
  char *fgets(char *s, int size, FILE *stream);
  功能:从指定的位置读一串字符
  参数:
     s:读到字符串存放的位置
	 size:期待读字符的个数
	     实际读到的个数是size-1个,留一个位置进行补‘\0’
		 遇到‘\n’,不再往后读字符
	 stream:文件流指针
  
 返回值:
   成功 :返回字符串存放的地址
   失败或读到文件结尾:NULL
  
7.fputs
  int fputs(const char *s, FILE *stream);
  功能:将字符串输出到指定文件中
  参数:s:输出内容
        stream:文件流指针

  返回值:成功:输出字符的个数
     失败:EOF
  
  
练习:用fgets实现wc -l file 的功能
****       buf:****\0   buf:\n\0
*******    buf:****\0   buf:***\n\0
******     buf:****\0   buf:**\n\0

while( fgets(buf,5,fd) != NULL)
{
  if(buf[strlen(buf)-1]=='\n')
      n++;	 
}		  
  
补充:对于main函数的参数
argc:命令行参数的个数
argv:  ---》char *argv[]  保存的是命令行参数的内容   ./a.out  hello  world


  int a=10,b=20,c=30;
  int *arr[3]={&a,&b,&c};//指针数据,数组,数组的元素是指针   
  
  char *ch[3]={"hello","world","welcome"};//char *p="hello";
   ==>  ch[0]="hello";  ch[1]="world"
	 printf("%s\n",ch[0]);

作业:
练习:用fgets和fputs实现cp的功能

/*************************************************************************
	> File Name: cpByC.c
	> Created Time: Sun 15 Aug 2021 09:14:10 AM CST
	> Author: noah
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

	FILE *fp1;
	char str[50];
	printf("plz input filename as source\n");
	scanf("%s", str);
	if ((fp1 = fopen(str, "r")) == NULL) {
		perror("fopen");
		exit(1);
	}
	char str2[50];
	printf("plz input filename as target\n");
	scanf("%s", str2);
	FILE *fp2;
	if ((fp2 = fopen(str2, "w+")) == NULL) {
		perror("fopen");
		exit(1);
	}
	while (fgets(str,50, fp1) != NULL) {
		fputs(str, fp2);
	}
	return 0;

}

验证全缓存的刷新条件,同时计算全缓存缓存的大小。

/*************************************************************************
	> File Name: fullBuffer.c
	> Created Time: Sun 15 Aug 2021 09:50:04 AM CST
	> Author: noah
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	FILE *fp;
    if((fp = fopen("20.txt", "w")) != NULL) {
        fprintf(fp,"%ld\n",fp->_IO_buf_end - fp->_IO_buf_base);
        printf("full buffer size: %ld\n",fp->_IO_buf_end - fp->_IO_buf_base);
    }

    return 0;
}

大佬写的求各种缓冲的大小

  1. 题目要求:编程读写一个文件test.txt,每隔1秒向文件中写入一行数据,类似这样:
    1, 2007-7-30 15:16:42
    2, 2007-7-30 15:16:43
    该程序应该无限循环,直到按Ctrl-C中断程序。
    再次启动程序写文件时可以追加到原文件之后,并且序号能够接续上次的序号,比如:
    1, 2007-7-30 15:16:42
    2, 2007-7-30 15:16:43
    3, 2007-7-30 15:19:02
    4, 2007-7-30 15:19:03
    5, 2007-7-30 15:19:04
/*************************************************************************
      > File Name: time.c
	  > Created Time: Sat 14 Aug 2021 05:13:43 PM CST
	  > Author: noah
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	FILE *fp;
	if ((fp = fopen("time.txt", "a+")) == NULL) {
		perror("fopen");
		exit(1);
	}
	char ch;
	int n = 1;
	char str[50];
	FILE *fp2;
	fp2 = fopen("time.txt", "r");
	while ((fgets(str, 50, fp2)) != NULL) {
		n++;
	}
	fclose(fp2);
	while (1) {
		time_t curTime = time(NULL);
		char *curDate = ctime(&curTime);
		printf("%d.", n);
		printf(curDate);
		fprintf(fp, "%d.", n++);
		fputs(curDate, fp);
		fflush(fp);
		sleep(1);
	}

	fclose(fp);
	return 0;

}

补充函数:

  1. fprintf
    int fprintf(FILE *stream, const char *format, ...);
    功能:以指定的格式向文件中输出

  2. sprintf
    int sprintf(char *str, const char *format, ...);
    功能:以指定的格式将内容存放到数组中 str

  3. time
    #include <time.h>
    time_t time(time_t *t);
    功能:获取系统从1970-01-01 00:00:00到当前时间的秒数
    参数:
    t:获取到的秒数
    返回值:
    成功:获取到的秒数
    失败:-1 更新errno

  4. localtime
    struct tm *localtime(const time_t *timep);
    功能:将1970-0 1-01 00:00:00到现在的秒数转换为年月日,时分秒
    参数:
    timep:时间(time获取的秒数)
    返回值:
    成功:返回保存时间结构的地址
    失败:NULL


struct tm {
      int tm_sec;         /* 秒 */
      int tm_min;         /* 分*/
      int tm_hour;        /* 小时 */
      int tm_mday;        /* 一个月的某一天 */
      int tm_mon;         /* 月 */
      int tm_year;        /* 年 */
      int tm_wday;        /* 一周的某一天 */
      int tm_yday;        /*一年中的某一天 */
      int tm_isdst;       /* daylight saving time */
 };
  1. ctime
    char *ctime(const time_t *timer)
    C 库函数 char *ctime(const time_t *timer) 返回一个表示当地时间的字符串,当地时间是基于参数 timer
    返回的字符串格式如下: Www Mmm dd hh:mm:ss yyyy 其中,Www 表示星期几,Mmm 是以字母表示的月份,dd 表示一月中的第几天,hh:mm:ss 表示时间,yyyy 表示年份。
    参数
    timer – 这是指向 time_t 对象的指针,该对象包含了一个日历时间。
    返回值
    该函数返回一个 C 字符串,该字符串包含了可读格式的日期和时间信息。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值