标准文件io

Day1 标准io介绍及缓冲区

“一切皆文件”

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

文件类型:
常规文件 r
目录文件 d
字符设备文件 c
块设备文件 b (u盘,磁盘)
管道文件 p
套接字文件 s
符号链接文件 l

标准io通过缓冲机制减少系统调用,实现更高效的效率

标准io------流

FILE
标准io用一个结构体类型来存放打开文件的相关信息
标准io所有的操作都是围绕着流来进行的

文本流/二进制流

标准io—流的缓冲类型

全缓冲
当流的缓冲区无数据或者无空间时才执行io操作
行缓冲
当在输入和输出遇到换行符时进行io操作
流和一个终端互联,典型的行缓冲
无缓冲
数据直接写入文件,流不进行缓冲

标准io—stdin,stdout,stderr
标准输入流 0 STDIN_FILENO
标准输出流 1 STDOUT_FILENO
标准错误流 2 STDERR_FILENO

Day2 文件的打开,关闭及代码实现

文件的打开
打开就是占用资源
文件的关闭
关闭就是释放资源

标准io—打开文件
下列函数可用于打开一个标准io流:
FILE *fopen(const char *path,const char *mode);
pash路径文件,mode模式
成功返回流指针;出错返回NULL;

在这里插入图片描述
文件的打开实现

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main(){
    FILE *fp;
    int i;
    fp = fopen("test.txt", "r");
    if (fp == NULL)
    {
        //printf("Error!\n");
        perror("fopen:");
        printf("fopen:%s\n",strerror(errno));
    }else{
        printf("File opened!\n");
      
    }
    
}

编译错误
‘errno’ undeclared (first use in this function)
printf(“fopen:%s\n”,strerror(errno));
表示error没有被定义
解决办法:如果是系统变量用include头文件,如果是自己的,手动定义

perror函数只需要一个stdio.h头文件,
strerror 需要string.h,和error.h两个头文件

文件的关闭实现
int fclose(FILE * stream);
flose()调用成功返回0,错误返回-1.
流关闭时自动刷新缓冲区并释放,
当一个程序终止,所有打开的流都会关闭,
流一旦关闭之后就不能执行任何操作,

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main(){
    FILE *fp;
    int fpret;
    int i;
    fp = fopen("test.txt", "r");
    if (fp == NULL)
    {
        //printf("Error!\n");
        perror("fopen:");
        printf("fopen:%s\n",strerror(errno));
    }else{
        printf("File opened!\n");
        fpret = fclose(fp);
        if (fpret == 0)
        {
          printf("file close sucess");  /* code */
        }else{
            perror("fclose:");
        
        }
        
      
    }
    

fclose()函数的入参stream必须保证为非空,否则出现段错误。

Day3 标准io的读写

按字符输入/输出
fgetc()/fputc() 一次读/写一个字符

在这里插入图片描述

在这里插入图片描述

#include<stdio.h>
int main(){
    FILE *fp;
    int rec;
    fp=fopen("file.txt","r");
    if (fp == NULL)
    {
        perror("Error while opening the file.\n");
        return 0;
    }
     
    rec = fgetc(fp);
    printf("get char=%c\n", rec);

}

在这里插入图片描述
打开文件后读取,是从文件开头开始读取,然后读取下一个,这里时FILE本身定义封装的时候的时候有一个隐藏的数据结构,读完一个后读写指针会后移。

调用getchar会阻塞 等待键盘输入,

bad file descriptor 很可能是文件打开模式错误(只读模式去写入,只写模式去读)

行输入(读取行)
char *gets(char *s);一般不使用,容易造成缓冲区溢出

char *fgets(char *s, int size,FILE *stream); 总是包含’\0’ 实际数据时size-1个数据

注意事项:
gets函数以及该被淘汰 不用了
fgets函数第二个参数的大小,输入的数据超过size只保存size-1,最后添加\0,输入的数据小于size-1 后面会自动添加换行符

行输出(写整行)
int puts(const char *s);

int fputs(const char *s,FILE *stream);

puts将缓冲区s中的字符串输出到stdout追加换行符
fputs不追加
一般两个都使用 printf包含以上两个函数所有的功能。

#include<stdio.h>
int main(){
    FILE *fp;
    char *ret;
    int i;
    char buff[100];
    fp=fopen("file.txt","r+");
if(fp==NULL){
    perror("fopen");
    return 0;
}
/* ret = fgets(buff,5,fp);
    if (ret==NULL)
    {
        perror("fgets");
        fclose(fp);
        return 0;
    }
    printf("buff=%s\n",buff);
}
*/
i = fputs("hello world",fp);
if(i==EOF){
    perror("fputs");
 
}
printf("jhhhhhhhhh");
fclose(fp);

}

Day4 二进制方式

按指定对象输入

按指定对象输出

二进制读写
文本文件和二进制文件的区别:
存储格式不同:文本文件只能存储文本,

计算机内码概念:

二进制方式的读写:
size_t fread(void *ptr,size_t size,size_t n,FILE *fp);
void *ptr 读取的内容
size_t size 读取的块大小
size_t n 读取的个数
FILE *fp 读取的文件指针
size_t fwrie(const void *ptr,size_t size,size_t n,FILE *fp);

成功返回读写的对象个数;出错时返回-1;
即可以读写文本文件,也可以读写数据文件(二进制文件)

 ret = fwrite(&stu,sizeof(stu),1,fp);

    if (ret == -1)
    {
        perror("fwrite");
        goto end;
    }else{
        printf("write struct student success\n");
    }
    
ret = fread(&stu2,sizeof(stu),1,fp);
if (ret == -1)
{
    
    perror("fread");
    goto end;
}
printf("name:%s\n",stu2.name);
printf("age:%d\n",stu2.age);
printf("sex:%s\n",stu2.sex);

这u但代码执行结束会发现读出来是乱码 这是因为第一次写入的时候指针已经指向了末尾,读自然也是从最后一位读,后面没有数据,自然就是乱码,这里一般采用关闭重新打开文件的方式,或者后续会学到的文件的指针移动

Day5 流的刷新定位

流的刷新
int fflush(FILE *fp);
成功返回0,出错返回-1.
将流缓冲区中的数据写入实际文件,
linux下只能刷新输出缓冲区,输入缓冲区丢弃。

#include<stdio.h>
#include<unistd.h>
int main(){
    //printf("abcdefg");
    //fflush(stdout);
    FILE *fp;
    fp=fopen("2.txt","w");
    if(fp==NULL){
        perror("fopen");
        return 0;
    }

    fwrite("abcdef",7,1,fp);
    fflush(fp);
    while(1){
        sleep(1);
        
    }
}

原本存在循环,所以无法将缓冲区的数据写入到实际文件当中,所以加上fflush函数刷新流 在就可以写入实际的文件当中

流的定位
long ftell(FILE *stream);
long fseek(FILE *stream,long offset,int whence);
void rewind(FILE *stream);
ftell()成功返回流的当前读写位置,出错时返回-1
fseek()定位一个流,成功时返回0,出错时返回-1
whence参数;SEEK_SET/SEEK_CUR/SEEK_END
SEEK_SET从据文件开头offset位移量为新的读写位置。
用a模式打开 fseek无效
offset参数:位移量,可正可负,
rewind()将流定位到文件开始位置
rewind(fp)相当于fseek(fp,0,SEEK_SET)
读写流时,当前读写位置自动后移
这三个函数只适用于2g以下的文件。

FILE *fp = fopen(“test.txt”,“r+”);
fseek(fp,0,SEEK_END;
fputc(“t”,fp)
#include<stdio.h>

int main(){
     FILE *fp;
    fp=fopen("2.txt","w");
    if(fp==NULL){
        perror("fopen");
        return 0;
    }

    fwrite("abcdef",6,1,fp);
    fseek(fp,-2,SEEK_CUR);
    fwrite("vvv",3,1,fp);

}

输出结果为abcdvvv。

Day6 格式化输入输出

格式化输出
sprintf
字符串
int sprintf(char *s,const char *fmt,…);

#include<stdio.h>
int main(){
    char buf[100]={0};
    int year = 2023;
    int month = 8;
    int day = 1;

    sprintf(buf,"%d-%d-%d",year,month,day);
    printf("%s",buf);
}

fprintf
文件
int fprintf(FILE *stream,从上图char * fmt,…);

成功时返回输出的字符个数,出错时返回EOF
使用起来很方便,强烈推荐

#include<stdio.h>

int main(){
    FILE *fp;
    int year=2023;
    int month=8;
    int day=1;

    fp = fopen("3.txt", "w");
    if (fp==NULL)
    {
        perror("fopen");
        return 0;
    }
    
    fprintf(fp, "%d-%d-%d",year,month,day);
   
    fclose(fp);
}

格式化输入
int fscanf(FILE *stream, const char *format, …);
int sscanf(const char *str, const char *format, …);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   int day, year;
   char weekday[20], month[20], dtm[100];
 
   strcpy( dtm, "Monday April 10 2023" );
   sscanf( dtm, "%s %s %d  %d", weekday, month, &day, &year );
 
   printf("%s %d, %d = %s\n", month, day, year, weekday );
    
   return(0);
}

Day7 标准IO练习

1、每隔1秒向文件1.txt写入当前系统时间,行号递增

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, const char *argv[])
{
	FILE *fp;
	time_t ctime;
	int linecount;
	struct tm *ctimestr;
	char buf[22];
 
	fp = fopen("test.txt","a+");
	if(fp == NULL){
		perror("fopen");
		return 0;
	}
 
	while(fgets(buf,22,fp) != NULL){
		if(buf[strlen(buf) - 1] == '\n'){
			linecount++;
		}
	}
 
	while(1){
		ctime = time(NULL);
	//	printf("ctime = %d\n",(int)ctime);
		ctimestr = localtime(&ctime);
		printf("%04d-%02d-%02d %02d:%02d:%02d\n",ctimestr->tm_year+1900,ctimestr->tm_mon+1,ctimestr->tm_mday,
				ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
		fprintf(fp,"%d, %04d-%02d-%02d %02d:%02d:%02d\n",linecount,ctimestr->tm_year+1900,ctimestr->tm_mon+1,ctimestr->tm_mday,
				ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
		fflush(fp);
		linecount++;
		sleep(1);
	}
	
	
	fclose(fp);
 
	return 0;
}

Day8:文件IO(概念、打开、读、写、关闭)

1、使用文件IO实现“每隔1秒向文件1.txt写入当前系统时间,行号递增”

#include<stdio.h>
#include<time.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
 
int main(int argc, const char *argv[])
{
	int fd;
	time_t ctime;
	struct tm *ctimestr;
	int ret;
	int linecount = 0;
	char buf2[100];
 
	fd = open("1.txt",O_RDWR|O_CREAT|O_APPEND, 0666);
	if(fd==-1){
		printf("open failed\n");
 
		return 0;
	}
 
 
	while(read(fd,buf2,strlen(buf2)) != 0){
 
		if (buf2[strlen(buf2)-1] == '\n'){
			linecount++;
		}
	}
 
 
 
 
	while(1){
		ctime = time(NULL);
 
		ctimestr = localtime(&ctime);
		printf("%d, %04d-%02d-%02d %02d:%02d:%02d\n",linecount,ctimestr->tm_year+1900,ctimestr->tm_mon+1,ctimestr->tm_mday,
				ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
		sprintf(buf2,"%d, %04d-%02d-%02d %02d:%02d:%02d\n",linecount,ctimestr->tm_year+1900,ctimestr->tm_mon+1,ctimestr->tm_mday,
				ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
 
 
		ret = write(fd,buf2,strlen(buf2));
		if(ret<0){
			perror("write");
			close(fd);
		}
			fflush(fd);
 
			linecount++;
			sleep(1);
		}
		close(fd);
	}

Day9:文件IO(概念、打开、读、写、关闭)

1、遍历一个文件夹下所有文件,并打印文件大小和日期

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
 
int main(int argc, const char *argv[])
{
	DIR * dir;
	struct dirent *dent;
	struct stat buf;
	dir = opendir("/home/linux/lv3/linklist1/");
	if(dir == NULL){
		perror("opendir");
		return 0;
	}
 
	while((dent = readdir(dir)) != NULL){
		stat(dent->d_name,&buf);
		struct tm *t = localtime(&buf.st_ctime);
		printf("create time>%04d-%02d-%02d %02d:%02d:%02d ",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
		printf("name>%-16s  size>%d\n",dent->d_name,(int)buf.st_size);
	}
 
	closedir(dir);
	return 0;
}

Day10:静态库和动态库的使用

1、静态库和动态库都有什么特点?他们的区别是什么?

静态库:
特点:
一般扩展名为(.a或.lib),这类的函数库通常扩展名为libxxx.a或xxx.lib 。
静态库在编译时被链接到目标文件中,程序运行时不需要再额外加载库文件。
可以在不同平台上编译相同的源代码,而无需考虑库的兼容性问题。
程序的执行速度比动态库快,因为所有的库函数都在编译时被链接到可执行文件中。
静态库的使用非常简单,只需要将库文件和头文件包含在项目中即可。
区别:
静态库的体积比较大,因为它包含了所有需要的函数和代码。
如果多个程序都使用同一个静态库,那么每个程序都会有一份完整的库文件,会占用较多的磁盘空间。
如果静态库更新了,需要重新编译程序才能使用新的库函数。

动态库:
特点:
动态函数库的扩展名一般为(.so或.dll),这类函数库通常名为libxxx.so或xxx.dll 。
动态库在程序运行时才会被加载,可以在程序运行时动态地链接和卸载库文件。
多个程序可以共享同一个动态库,节省磁盘空间。
动态库的更新只需要替换库文件,程序不需要重新编译。
动态库可以提供插件功能,允许程序在运行时加载外部库。
区别:
动态库的执行速度比静态库慢,因为需要在程序运行时加载和链接库文件。
动态库的使用相对复杂,需要在程序中显式地加载和卸载库文件。
动态库的兼容性问题比较复杂,不同操作系统和编译器可能需要不同版本的库文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值