IO之标准IO

目录

1.标准IO

1.1.Linux的文件类型

1.2.标准IO与文件IO的区别

1.3流

1.4流的类型

1.5缓冲区类型

2.标准IO相关库函数

(1)打开文件 --fopen

(2)关闭文件 ---fclose()

(3)按字节读写 fgetc()/fputsc()

(4)按行读写 fgets()/fputs()

(5)按对象读写 fread()/fwrite()

(6)刷新流---fflush()

(7)定位文件 ftell()/fseek()/rewind()

(8)错误判断--feof()


1.标准IO

1.1.Linux的文件类型

普通文件         - / r

目录文件         d

管道文件         p         在内核创建

字符设备文件  c         每次输入输出是单字节

块设备文件     b         一块数据输入输出

链接文件         l        ln -s生成链接文件(软链接)

套接字文件     s         网络通讯

注意:不同的操作系统适用的文件类型不同

1.2.标准IO与文件IO的区别

标准IO遵循ANSI C标准,标准IO实际上是调用标准C库中的函数

特点:

标准IO利用缓冲机制,减少系统调用次数,从而提高程序运行效率

系统调用:不同操作系统接口不一样,通过接口调用硬件,称为系统调用,也就是通过函数来调用

缓冲机制:缓冲区,连续空间,一次把全部需要的全部读取,在内存中存储也就是存储在缓冲区,每次使用时不涉及系统调用

 

标准IO--高级IO fread 有缓冲区 无实时性

文件IO--低级IO read 无缓冲区 实时性

标准IO是在文件IO的基础上做的一次再封装

有缓冲区无实时性,满足不了一些特殊设备的要求,例如摄像头等

标准IO一般用于操作普通文件

1.3流

数据仅是简单的从文件进行流入和流出,我们把这种现象称为流

流在文件中用,FILE结构体描述。在一个程序中一个文件对应一个FILE结构体

grep -r "_IO_FILE" /usr/include/ 查找FILE结构体

/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h

:/ _IO_FILE

struct _IO_FILE


    int _fileno 文件描述符
    char *_IO_buf_base;缓冲区的起始地址
    char *_IO_buf_end;缓冲区的末尾地址
    ...

};

三个特殊的流: 打开文件后,默认打开

标准输入流:-- stdin --键盘设备

标准输出流:--stdout --终端设备

标准错误流:--stderr --特殊终端,输出错误

printf("stdin=%d",stdin->_fileno);//打开一个文件就自己宏定义了stdio

标准输入流 编号为0

标准输出流 编号为1

标准错误流 编号为2

之后的FIlE文件编号从3开始

1.4流的类型

流的类型有两种:文本流、二进制流。

区别:

处理数据的方式不一样。

处理字符数字时不一样。

处理换行符的方式不一

(1)文本流:以字符的方式来处理,将输入输出的数据转换成对应的ASCII码,再进行存取。最后还是转成二进制。

"1234" ----> 49 50 51 52

‘\n’ ---> ‘\r '\n’ (加上\r)(windows)

(2)二进制流:以二进制数字的方式来处理,将数据转换为二进制进行存取

"1234" ----> 看做整数 1234 ,0100 1101 0010

'\n' ---'\n' 换行符不做特殊处理

在linux中,没有对文本流和二进制流作区分,换行符不做特殊处理

打开文件时,可以选择流的类型选择

1.5缓冲区类型

(1)全缓冲:打开一个文件时,默认使用全缓冲,当缓冲区满或空时,才进行IO操作。

满时进行写操作,程序结束时,会把缓冲区刷新(写入),空时进行读操作(数据取完才进行下一次读操作)

(2)行缓冲:当输入输出与终端相关时,使用行缓冲。当缓冲区满(1024)或遇到换行符时,才进行实际的IO操作,程序结束后所有缓冲区刷新

eg:

printf("hello");

while(1);

执行程序时,hello会在行缓冲区中,没打印

(3)无缓冲:与错误输出相关,使用无缓冲(错误需要实时性)(不使用缓冲区),直接输出

2.标准IO相关库函数

fopen()/fclose() --打开/关闭文件

fgetc()/fputc() --按字节读写文件

fgets()/fputs() --按行读写文件

fread()/fwrite() --按对象读写文件

ftell()/fseek()/rewind() --定位文件指针

每打开一个文件就有一个文件指针指向开头

文件指针:定义了读写的位置,每读写一个字符,自动向后偏移1位

fflush() --刷新流,强制刷新缓冲区。提前进行IO

feof()/ferror() --判断错误

man手册:

1.shell指令和可执行程序 ls

2.系统调用函数

3.标准库函

(1)打开文件 --fopen

#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);

参数:pathname:要打开文件的文件名,字符串型的,没写路径默认当前路径
    mode:打开文件的方式(r,r+,w,w+)
    r:    以只读的方式打开文件,文件不存在则无法打开
    r+:    以读写的方式发开文件,文件不存在则无法打开
    w:    以只写的方式打开文件,文件不存在就创建新的
    w+:    以读写的方式发开文件,文件不存在就创建新的
    a:    以只写,追加的方式(另起一行)打开文件,文件不存在就创建新的
    a+:以读写,追加的方式发开文件,文件不存在就创建新的
返回值:成功返回对应的文件的流指针,失败返回NULL,并设置错误号(errno)

erron:当前系统中最后一个错误的编号
要显示时加上头文件#include <erron.h>

#include <string.h>
char *strerror(int errnum);//打印错误信息
参数:    errnum错误号
返回值:错误原因

#include <stdio.h>
void perror(const char *s);
参数:s表示提示信息

显示结果:提示信息 错误原因

(2)关闭文件 ---fclose()

#include <srdio.h>
int fclose(FILE *stream);
参数:    stream甘比文件对应的流指针
返回值:成功返回0,失败返回“EOF”(-1)

        

程序结束时,程序中打开的文件会自动关闭

(3)按字节读写 fgetc()/fputsc()

#include <stdio.h>
int fgetc(FILE *stream);
参数:stream:FILE流指针
返回值:成功返回获取到的字符,失败返回-1,读到文件末尾也会返回-1.feof()判断错误流。可以区分什么导致的-1.

#include <stdio.h>
int fputc(int c, FILE *stream);
参数:c 要写入的字符,stream    FILE流指针
返回值:成功返回写入的字符,失败返回-1。

练习:1.计算文件大小
     2.用fgetc()和fputc()完成文件的拷贝

/*===============================================
*   文件名称:length.c
*   创 建 者:     
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#include <stdio.h>

int main(int argc, char *argv[])
{ 
    if(argc!=3)
    {
        printf("Usage:%s <src_filename> <dest_filename>",argv[0]);
        return -1;
    }
    //FILE *fp1=fopen("1.txt","r+");	//打开文件
    FILE *fp1=fopen(argv[1],"r+");
    if(NULL==fp1)
    {
        perror("fopen 1");
        return -1;
    }
    //FILE *fp2=fopen("2.txt","w+");
    FILE *fp2=fopen(argv[2],"w+");	//打开文件
    if(NULL==fp2)
    {
        perror("fopen 2");
        return -1;
    }

    int i=0,ch;
    while((ch=fgetc(fp1))!=-1)	//循环中i计数,通过ch一个一个字符复制
    {
        i++;
        fputc(ch,fp2);
        printf("%5d",ch);
    }
    printf("length is %d\n",i);
    fclose(fp1);
    fclose(fp2);
    return 0;
} 

(4)按行读写 fgets()/fputs()

#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
参数:s 字符串首地址,读取数据到s内。
    size 读取数据的最大长度。
    stream FILE流
返回值:成功返回读取数据的首地址,失败返回NULL,文件读取完也会是NULL.
注意:1.当读取内容遇到换行符,读取结束
    2.最大读取内容为 size-1 ,最后一个字符补上'\0'
    3.会把换行符也获取。

    
#include <stdio.h>
int fputs(const char *s, FILE *stream);
参数:s 字符串首地址,把s字符串写入File流
    stream FILE流
    
返回值:成功返回非零值,失败返回-1
练习:打开一个文件,统计该文件的行数

/*===============================================
*   文件名称:hangshu.c
*   创 建 者:     
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#include <stdio.h>
#include <string.h>
#define n 5

int main(int argc, char *argv[])
{ 
    FILE *fp = fopen("1.txt","r+");
    if(NULL==fp)
    {
        perror("fopen");
        return -1;
    }

    char buf[n]={0},i=0;
    
    while(fgets(buf,n,fp)!=NULL )	//循环统计
    {
        
        //if(buf[n-2]=='\n'|| strlen(buf)<n-1)
        if(buf[strlen(buf)-1]=='\n')//读取完有两种情况,1.没存满,提前遇见\n	2.存满
        {
            i++;
        }
        memset(buf,0,n);	//以防没有覆盖干净
    }
    printf("line=%d\n",i);

    return 0;
} 

(5)按对象读写 fread()/fwrite()

#include <stdio.h>

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);

参数:ptr 存放字符串的首地址
    size 一个对象大小    
    nmemb 一次读的对象个数
    stream 流指针

返回值:成功返回读到的对象的个数(nmemb),失败或读完,返回0。
fwrite(buf, sizeof(char), 1 ,fp);

(6)刷新流---fflush()

#include <stdio.h>
int fflush(FILE *stream);
       
参数:stream 流指针
返回值,成功返回0,失败返回-1

(7)定位文件 ftell()/fseek()/rewind()

#include <stdio.h>

long ftell(FILE *stream);

功能:返回文件指针相对了文件开头的偏移量
参数:流指针
返回值:return current offset
      成功返回当前的偏移量,失败返回-1

int fseek(FILE *stream, long offset, int whence);

功能:定位指针,最后的定位位置=offset+whence
参数:stream 流指针
    offset 偏移量,可以为负数。
    whence 表示基准点,可以设置为以下
    SEEK_SET:将文件指针定位在文件开头
    SEEK_CUR:将文件指针定位在当前位置
    SEEK_END:将文件指针定位在文件末尾
返回值:成功返回0,失败返回-1.


void rewind(FILE *stream);
功能:将文件指针定位在文件开头
参数:流指针

(8)错误判断--feof()

#include <stdio.h>
int feof(FILE *stream);
参数:
返回值:返回1        表示流访问结束(文件读完了)
      返回0      表示错误返回

作业:

打开一个文件,向文件中每隔1s记录当前行数和时间

/*===============================================
*   文件名称:homework.c
*   创 建 者:     
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <time.h>

int main(int argc, char *argv[])
{ 
    int n=0,sec,i;				//n
    time_t my_t;                    //为输出时间做准备
    time(&my_t);
    struct tm *t=localtime(&my_t);

    FILE *fp = fopen("1.txt","a+");

    char buf[64]={0};
    while(fgets(buf,64,fp)!=NULL)//统计有几行
    {
       if(buf[strlen(buf)-1]=='\n')
        {
            n++;
        }
       memset(buf,0,64);
   }
	
    sec=t->tm_sec;
    while(1)
    {   
    	time(&my_t);	//为了保证秒钟会变
    	struct tm *t=localtime(&my_t);
    	
        if((sec+1)==t->tm_sec)
        {

            fprintf(fp,"%3d  %d年-%d月-%d日 %d时:%d分:%d秒\n",++n,t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
            fflush(fp);		//刷新缓冲区,把数据写入文件
            sec=t->tm_sec;
            if(sec==59)//用于秒数迭代,0~59
            {
            	sec=-1;
            }
        }
    }
    return 0;
} 

运行结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值