文件IO(标准文件IO)

前言

        本文记录标准文件IO,即标准C库提供的针对文件打开读写操作的函数。

文件IO

        文件的读写操作就叫文件IO
        文件IO分为两类:
                (1)标准文件IO        就是标准C库提供的针对文件打开读写操作的函数;
                (2)系统文件IO        就是Linux系统提供答完针对文件打开读写操作的函数。

标准文件IO和Linux文件IO区别

        (1)标准文件IO存在缓存区,Linux文件IO不存在缓存区;
        (2)标准文件IO只能打开普通文件,Linux文件IO可以打开不同类型的文件(管道文件、套接字文件);
        (3)标准文件IO用FILE*文件流指针来识别每个文件,Linux文件IO用in fd文件描述符来识别每个文件;
        (4)两者的提供函数不同。

标准文件IO

        标准文件IO存在文件缓冲区,减少系统开销。(重点)

全缓存

        需要经过缓存区,缓存区(默认1024字节)满了一次性打印在终端上。

int main()
{
    while(1)
    {
        printf("hello world");    //此处不加\n
        sleep(1);
    }
    return 0;
}

行缓存

        加上\n不经过缓存区,直接将内容输出到终端上

int main()
{
    while(1)
    {
        printf("hello world\n");    //此处加\n
        sleep(1);
    }
    return 0;
}

标准文件IO相关函数 

fopen函数

#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
//调用参考
FILE* fp  = fopen("./hello.txt","r");    //绝对路径,以只读方式打开当前路径下的hello.txt

        功能:打开文件

        参数1:打开文件的路径,可以是相对路径或者绝对路径
        参数2:打开文件的方式

"r"只读的方式打开文件
"r+"可读可写的方式打开文件
"w"只写的方式打开文件
如果文件不存在,创建文件以只写方式打开;
如果文件存在,清空再以只写方式打开。
"w+"可读可写的方式打开文件
如果文件不存在,创建文件以可读可写方式打开;
如果文件存在,清空再以可读可写方式打开。
"a"文件末尾写追加信息的方式打开
文件不存在,创建文件以末尾追加方式打开;
文件存在,不清空追加写方式打开。
"a+"以可读末尾写追加的方式打开

        返回值:成功,返回FILE*(打开的文件在内核中的首地址);失败,返回NULL。
                FILE*指针,文件流指针,FILE是一个结构体,每打开一个文件,内核就会为这个文件开辟内存空间来保存打开文件的相关内容。 

fgetc函数

#include <stdio.h>
int fgetc(FILE *stream);
//调用参考
char ch = fgetc(fp);

        功能:每次读取一个字符
        参数:文件流指针,fopen函数的返回值
        返回值:成功,返回对应的ASCII码值;
                      失败,返回EOF(读取到文件末尾时返回EOF,循环读取时,可作为结束标识)                             #define EOF -1

fputc函数 

#include <stdio.h>
int fputc(int c, FILE *stream);

        功能:每次写入一个字符
        参数1:写入的字符
        参数2:文件流指针,fopen函数的返回值     
        返回值: 成功,返回写入字符;失败,返回-1。

fclose函数

        关闭打开的文件之前刷新缓存区,才会把读写内容写入到文件中。之后再关闭释放空间。

int fclose(FILE *fp);

perror函数

#include <stdio.h>
void perror(const char *s);

        功能:打印错误原因
        参数:打印错误原因前的提示信息

strerror函数

#include <string.h>
char *strerror(int errnum);
//调用参考
printf("fopen failed:%s\n",strerror(errno));

        功能:打印错误提示信息,但是需要错误信息编号作为参数。
                   Linux系统下有一个int类型的全局变量errno,即错误信息的编号
       
参数:错误编号
        返回值:返回错误原因字符串的首地址。

fgets函数

        读取到文件末尾的标识是NULL;当buf数组长度不够存放读取的一行内容时,最多读取sizeof(buf)-1,最后一位存放'\0'。字符串必须以\0结尾。

#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);

        功能:每次读取一行(以\n作为读取的终止符)

        参数1:读取出来的一行内容
        参数2:一次最多读取的字节数
        参数3:文件流指针,fopen函数的返回值

        返回值:成功,读取到内容的首地址;失败,返回NULL。

案例
#include <stdio.h>
int main()
{
	char buf[100] = {0};
	//以可读的模式打开文件
	FILE *fp = fopen("./fgets.c","r");
	if(NULL == fp)
	{
		//使用perror函数打印出具体的错误提示信息
		perror("fopen failed reason");
		return -1;
	}
	//循环读取文件中的所有内容
	while(fgets(buf,sizeof(buf),fp) != NULL)
	{
		printf("%s",buf);
	}
	//关闭文件
	fclose(fp);
	return 0;
}

fputs函数

#include <stdio.h>
int fputs(const char *s, FILE *stream);

        功能: 一次写入一行
        参数1:存放要写入的字符串首地址
        参数2:文件流指针,fopen函数的返回值

        返回值:成功,返回实际写入的字符数;失败,返回EOF

案例
#include <stdio.h>
int main()
{
	char buf[100] = {0};
	FILE *fp = fopen("./fgets.c","r");	
	FILE *fp1 = fopen("./demo.c","w");
	if(NULL == fp||NULL == fp1)
	{
		perror("fopen failed reason");
		return -1;
	}
	//循环读取文件中的所有内容
	while(fgets(buf,sizeof(buf),fp) != NULL)
	{
		fputs(buf,fp1);
	}
	fclose(fp);
	fclose(fp1);
	return 0;
}

fflush函数

        手动刷新缓存区,防止中断结束内容未写到文件中,实现写入一次,成功一次。

//for循环输入三个名字,保存到name.txt中
#include <stdio.h>
#include <string.h>
int main()
{
    char buf[128];    //保存要写入的字符串
    FILE *fp = fopen("./name.txt","w");
    if(NULL == fp)
    {
        perror("fopen failed");
        return -1;
    }
    for(int i = 0;i < 3;i++)
    {
        scanf("%s",buf);
        //输入2次名字后,按ctrl+c提前结束程序,发现前两次写入名字失败,因为标准IO存在缓存区
        //加上fflush(fp)函数,可实现写入一次成功一次
        srtcat(buf,"\n");    //拼接一个\n
        fputs(buf,fp);
        //写入后手动刷新缓存区
        fflush(fp);
    }
    fclose(fp);
    return 0;
}

案例:模仿cp命令,实现内容拷贝,命令行传参./cp a.c b.c

#include <stdio.h>
int main(int argc,const char *argv[])
{
	//参数校验
    if(argc != 3)
    {
        printf("传递参数有误\n");
        return -1;
    }
    char buf[128] = {0};
	FILE *fp_r = fopen(argv[1],"r");	
	FILE *fp_w = fopen(argv[2],"w");
	if(NULL == fp||NULL == fp1)
	{
		perror("fopen failed reason");
		return -1;
	}
	//循环读取文件中的所有内容
	while(fgets(buf,sizeof(buf),fp_r) != NULL)    //文件内容读取
	{
		fputs(buf,fp_w);    //写入另一个文件
	}
	fclose(fp_r);
	fclose(fp_w);
	return 0;
}

fread函数

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//size_t的类型原型是
typedef int size_t
//调用参考
char buf[100];
fread(buf,50,2,fp);    //一个基本单位50,最多读取2块

        功能:以指定大小读取文件内容,一次读取一段内容,以块为单位。
        参数:void *ptr         读取内容的首地址
                   size_t size         一块的大小(一块是一个基本单位)以字节为单位
                   size_t nmemb         一次最多读取的块数
                   FILE *stream         文件流指针,fopen函数的返回值
        返回值:成功,返回实际读取的块数、实际读取的对象数、实际读取的记录数;
                      
失败,返回小于0的数。

案例
#include <stdio.h>
#include <string.h>
int main()
{
	FILE *fp = fopen("./fread.c","r");
	if(NULL == fp)
	{
		perror("fopen failed reason");
		return -1;
	}
	char buf[100] = {0};
	while(fread(buf,1,sizeof(buf),fp) > 0)
	{
		printf("%s",buf);
		memset(buf,0,sizeof(buf));	//将整个数组都置为0
	}
	fclose(fp);
	return 0;
}

 fwrite函数

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

        功能:按照块写入(可以二进制的方式写入)

        参数1:即将写入文件数据存放的位置
        参数2:一块的大小
        参数3:实际想要写入的块数
        参数4:fopen函数的返回值

        返回值:成功,实际写入的块数;失败,小于0 

sprintf和fprintf函数

#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);

memset函数

#include <string.h>
void *memset(void *s, int c, size_t n);

        功能:内存设置函数,是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。
        返回值:被设置的内存空间的起始地址。

fseek函数

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

        功能:文件指针是FILE结构中的一个成员变量,移动文件指针的位置

        参数1:fopen的返回值
        参数2:偏移量(正数---向后移动,负数---向前移动)
        参数3:基准值,相对位置
                        SEEK_SET        文件头
                        SEEK_END       文件尾
                        SEEK_CUR       文件当前光标位置

        返回值:成功,0;失败,EOF  -1 

ftell函数

long ftell(FILE *stream);

        功能:获取文件指针的位置,文件指针的位置下标从0开始。

        参数:fopen的返回值

        返回值:成功,返回当前文件光标的位置;失败,EOF。

标准IO三个流(重点) 

        一个程序运行时,会自动打开三个流。

标准(standard)输入流stdin默认是键盘
标准输出流stdout默认是终端
标准错误流(无缓存)stderr默认是终端

time ctime和localtime

#include <time.h>
time_t time(time_t *tloc);
//调用
time(0);
time(NULL);    //NULL -- 0

        功能:获取从1970-01-01 00:00:00 +0000 (UTC)距今的秒数。 

char *ctime(const time_t *timep);

        功能:将距今的秒数,转换成英文格式的系统时间

        参数:距今的秒数

        返回值:英文格式时间字符串的首地址

struct tm *localtime(const time_t *timep);
//
struct tm
{
    int tm_sec;   /* Seconds (0-60) */
    int tm_min;   /* Minutes (0-59) */
    int tm_hour;  /* Hours (0-23) */
    int tm_mday;  /* Day of the month (1-31) */
    int tm_mon;   /* Month (0-11) */
    int tm_year;  /* Year - 1900 */
    int tm_wday;  /* Day of the week (0-6, Sunday = 0) */
    int tm_yday;  /* Day in the year (0-365, 1 Jan = 0) */
    int tm_isdst; /* Daylight saving time */
};

        功能:距今的秒数,转换成年 月 日 小时 分钟 秒 具体时间,格式化为中文格式 

使用实例 
#include <stdio.h>
#include <time.h>
int main(int argc, const char *argv[])
{
    time_t t;             // 保存距今的秒数
    struct tm *tp = NULL; // 用来保存localtime返回值
    time(&t);             // 得到距今的秒数
    // 因为ctime返回值是英文格式字符串首地址,可以直接用%s输出
    printf("%s", ctime(&t));
    tp = localtime(&t); // 将距今的秒数转换为具体时间
    printf("%d-%02d-%02d %02d:%02d:%02d\n", tp->tm_year + 1900, tp->tm_mon + 1,
           tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值