当前位置: 首页 > news >正文

Linux应用(2)——标准/目录IO

一、简介

第一类:C语言阶段操作过的--只能对特殊文件操作
scanf  printf   getchar putchar  gets  puts
第二类:新增的--可以对特殊文件操作,也可以是对普通文件操作
fopen   fclose   fread  fwrite  fseek
fscanf   fprintf  fgetc  fputc   fgets  fputs
feof   fflush

1.1 文件IO特点

  1. 文件IO可以对普通文件操作,也可以对特殊文件操作
  2. 文件会存在文件指针,当open打开文件时,文件指针默认在文件开始处,对文件的读写,都会造成文件指针的偏移(以字节为单位),当close关闭后,文件指针默认在文件末尾
  3. 文件IO的读写函数没有缓冲区,读写是马上生效的,是一种低速IO
  4. read 输入--> 文件数据的读取  write 输出--->数据存放到文件

1.2 标准IO特点

  1. 标准IO可以对普通文件操作,也可以对特殊文件操作
  2. 文件会存在文件指针,当fopen打开文件时,文件指针默认在文件开始处,对文件的读写,都会造成文件指针的偏移(以字节为单位),当fclose关闭后,文件指针默认在文件末尾
  3. 标准IO的读写函数存在缓冲区,读写不会马上生效,当满足条件才生效,是一种高速IO
  4. 标准IO存在多种读写方式,读函数---输入   写函数---输出
    标准IO 的读写通常配套使用
    第一对读写:fscanf   fprintf   格式化读写
    第二对读写:fgetc  fputc     单字符读写
    第三对读写:fgets  fputs     字符串读写
    第四对读写:fread  fwrite    全缓存读写

1.3 缓存特点

分类:

---针对的读写函数
无缓存: 文件IO  中的  read  write
行缓存:   标准IO  剩余的都是行缓存
scanf  printf   getchar putchar  gets  puts
fscanf   fprintf  fgetc  fputc   fgets  fputs
全缓存:   标准IO   fread  fwrite

行缓存满足条件
在常规开发过程中,用户无需记忆缓存的满足条件,因为默认常规下都是满足的
------满足以下任意一个即可
输入输出存在换行符 

输入: ---回车结束;

输出: ---输出 ‘\n’

  1. 程序自然结束,没有死循环
  2. 程序中采用 fclose关闭文件
  3. 程序中采用fflush 刷新缓冲区
  4. 写满该行  大致 1024字节

全行缓存满足条件

 ------满足以下任意一个即可

  1. 程序自然结束,没有死循环
  2. 程序中采用 fclose关闭文件
  3. 程序中采用fflush 刷新缓冲区
  4. 写满全缓存  大致 4K 字节

1.4 文件IO与标准IO对比

对比

文件IO

标准IO

用途上

用途1:实现应用层数据的存取,不丢失

用途2:实现驱动和应用的数据交流

用途1:实现应用层数据的存取,不丢失 用途2: 实现驱动和应用的数据交流

对文件操作上

可以对普通文件操作,也可以对特殊文件操作;普通文件需要先打开在读写;特殊文件直接读写

可以对普通文件操作,也可以对特殊文件操作;普通文件需要先打开在读写;特殊文件直接读写

文件指针

文件会存在文件指针,当open打开文件时,文件指针默认在文件开始处,对文件的读写,都会造成文件指针的偏移(以字节为单位),当close关闭后,文件指针默认在文件末尾

文件会存在文件指针,当fopen打开文件时,文件指针默认在文件开始处,对文件的读写,都会造成文件指针的偏移(以字节为单位),当fclose关闭后,文件指针默认在文件末尾

缓冲区

无缓存,读写马上生效,低速IO

有缓存,读写满足条件才生效,高速IO

文件ID

int fd   文件描述符

FILE *fp  文件流指针

应用平台

#include <unistd.h>

只能在linux环境下运行

#include <stdio.h>

可以在linux环境下运行,也可以在win下运行

特殊文件

文件IO--文件描述符/fd

标准IO--文件流指针/fp

标准输入

0

stdin

标准输出

1

stdout

标准错误

2

stderr

普通文件

默认从3开始分配

二、标准IO函数

2.1 fopen,fclose

打开/关闭函数应用

头文件   :#include<stdio.h>
函数原型:FILE * fopen(const char * path,const char * mode)
函数参数:
@param1
      const char * path  : 带路径的文件名
@param2
const char * mode : 打开权限
r  :  只读方式,打开已存在的文件
w :  覆盖方式打开只写文件,如果文件存在就覆盖在打开,如果文件不存在就创建
a : 追加方式打开只写文件,如果文件存在就追加在打开,如果文件不存在就创建
      +: 可读可写
      b : 以二进制方式
r+  可读可写方式,打开已存在的文件
w+ 覆盖方式打开 可读可写文件,如果文件存在就覆盖在打开,如果文件不存在就创建
a+ 追加方式打开可读可写文件,如果文件存在就追加在打开,如果文件不存在就创建
注意事项:  'r'   错误的   ; "r"   正确的
函数返回值:
成功: 返回文件的ID--文件流指针
失败:  NULL
函数功能:以指定方式(是否存在、文件权限) 打开文件
函数特性:
fopen成功后,文件指针默认在文件开始处
可以利用对同个文件的多次打开,实现把文件指针偏移到文件开始处;同样也可以利用fseek函数实现

头文件:#include<stdio.h>
函数原型:int fclose(FILE * stream);
函数参数:FILE * stream   文件流指针
函数返回值: 应用不多
若关文件动作成功则返回 0,有错误发生时则返回 EOFstruct _IO_FILE {
函数功能:关闭文件

2.2 fgetc,fputc

单字节读写函数应用

头文件 #include<stdio.h>
函数原型:int fgetc(FILE * stream); 
函数参数:FILE * stream 文件流指针, 从哪个文件中读取数据
函数返回值:读到的字符;如果 返回 EOF就说明到文件尾部
函数功能:从文件中读取一个字节数据--读函数--输入---数据 从文件到应用 buf
函数特性:
读操作会引起文件指针的偏移
int ch = fgetc(stdin);  等价于   int  ch=getchar();

头文件:#include<stdio.h>
函数原型:int fputc(int c,FILE * stream);
函数参数:
@param1
 int c  : 要写入的字符
 @param2 FILE * stream: 文件流指针,要写到哪个文件中
函数返回值:--应用不多
返回写入成功的字符
函数功能:把一个字符写入文件---写函数--输出---数据 从 应用 buf 到文件
函数特性:
写操作会引起文件指针的偏移
fputc('\n',stdout);   等价于   putchar('\n');

2.3 fgets ,fputs

字符串读写函数应用

头文件:#include<stdio.h>
函数原型:char * fgets(char * s,int size,FILE * stream);
函数参数:
@param1   
char * s :  应用层 buf 数组
@param2   int size : 一次读取的字节数
@param3   FILE * stream: 文件流指针--从哪个文件读
函数返回值:
成功则返回 s 指针,
返回 NULL 则表示有错误发生。
函数功能:读函数---输入--数据从 文件 到 buf ,从FILE * stream文件中读取size字节到应用层s所指向的内存中
函数特性:
读操作会引起文件指针的偏移
函数返回值不能作为读取到文件尾部的判断依据,需要借助于其他函数 feof

头文件:#include<stdio.h>
函数原型:int fputs(const char * s,FILE * stream);
函数参数:
@param1  const char * s:  内存
@param2  FILE * stream :  文件
函数返回值:应用不多  ,int  实际写入的字符个数
函数功能:写函数--输出---数据从内存s到文件 把内存s中的所有有效字符 输出到 stream文件中
函数特性:
写操作会引起文件指针的偏移
写入函数无指定 size字节数,是把s内存地址中所有有效字符都写入
---所以在使用fgets ,fputs 最好保证 一次读写的字节数相同

注意事项:
fgets  fputs  这对字符串读写 应用不多--使用麻烦
1.fgets函数返回值不能作为文件尾部的判断依据,需要额外引入feof函数
2.fputs函数无指定写入字节数,是把所有有效字符都写入,需要注意应写入的字节个数

2.4 fscanf  fprintf 

格式化读写函数应用

头文件:#include<stdio.h>
函数原型:
int fscanf(FILE * stream ,const char *format,....);
int scanf(                      ,const char *format,....);//  相当于文件流指针固定是  stdin
函数参数:
@param1   FILE * stream : 文件流指针--读哪个文件
@param2  const char *format: 格式化控制 %c   %d  %f  %s
....  : 内存地址列表
函数返回值:使用不多 成功则返回参数数目,失败则返回-1,
函数功能:从指定文件中格式化读取数据到内存--取
函数特性:
1.读操作会引起文件指针的偏移
2.要借助于 feof函数对文件尾部判断
int  num;float sorce;char buf[20];
scanf("%d %f %s",&num,&sorce,buf); 等价于fscanf(stdin ,"%d %f %s",&num,&sorce,buf);

头文件:#include<stdio.h>
函数原型:int fprintf(FILE * stream, const char * format,.......);
函数参数:
@param1 
FILE * stream : 文件流指针--写到哪个文件
@param2 const char *format:格式化控制 %c   %d  %f  %s
....                          : 输出列表
函数返回值:使用不多,成功则返回实际输出的字符数目,失败则返回-1,
函数功能:把内存中格式化数据写入到文件--存
函数特性:1.写操作会引起文件指针的偏移

2.5 printf  fprintf sprintf 对比

int fprintf(FILE * stream, const char * format,.......);  // 格式化输出到指定文件
int printf( ,const char *format,....);                             // 格式化输出到屏幕
int sprintf(char *buf , const char * format,.......);      //格式化输出到char buf中-实际上就是实现 int/float 转换成 char

2.6 fflush feof

头文件:#include<stdio.h>
函数原型:int fflush(FILE* stream);
函数参数:FILE* stream: 文件流指针
函数返回值:成功返回 0,失败返回 EOF
函数功能:刷新缓存区

头文件 #include<stdio.h>
函数原型:int feof(FILE * stream);
函数参数:FILE * stream: 文件流指针--要检测的文件
函数返回值:
==0: 没有到文件尾部
!=0:    已到达文件尾
函数功能:判断是否已经到文件尾部

2.7 fread,fwrite全缓存读写函数

头文件:#include<stdio.h>
函数原型:size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream);
函数参数:
  @param1:void * ptr  :  应用层内存buf
  @param2: size_t size  : 每块的字节数 
  @param3: size_t nmemb: 读取的块数
  @param4 FILE* stream: 文件流指针--从哪个文件中读
一次读取的字节总数= nmemb *size
函数返回值:可以作为文件尾部的判断依据
返回实际读取到的 nmemb 数目
函数功能:读函数--输入--数据从文件到内存buf ,从文件中读取内容到应用内存buf

头文件:#include<stdio.h>
函数原型:size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream);
函数参数:
@param1 
constvoid * ptr  :  应用层内存buf
   @param2 size_t size  : 每块的字节数 
   @param3 size_t nmemb: 写入的块数
   @param4 FILE* stream: 文件流指针--要写到哪个文件
一次读取的字节总数= nmemb *size
函数返回值:使用不多
返回实际写入的 nmemb 数目
函数功能:写函数--输出--数据从内存buf 到文件,把应用内存buf中的数据存入文件

三、标准IO练习

1.利用标准io实现fgetc  fputc  实现  cp 拷问文件命令的重写

/*利用标准io实现fgetc  fputc  实现  cp 拷问文件命令的重写*/
#include <stdio.h>int main(int argc,char *argv[])
{//定义文件流指针FILE*fpsrc,*fpobj;//定义接收用int ch;if(argc!=3){printf("复制格式错误!\n");return -1;}//打开源文件,源文件必须存在fpsrc=fopen(argv[1],"r");if(fpsrc==NULL){printf("源文件打开失败!\n");return -1;}//打开目标文件,目标文件不存在fpobj=fopen(argv[2],"w");if(fpobj==NULL){printf("目标文件打开失败!\n");return -1;}while(1){//从源文件中读内容ch=fgetc(fpsrc);if(ch==EOF)break;//将读到的内容放到目标文件fputc(ch,fpobj);}fclose(fpsrc);fclose(fpobj);return 0;
}

2.利用标准io实现fgets  fputs  实现  cat 命令的重写

/*利用标准io实现fgets fputs实现cat命令的重写*/
#include <stdio.h>int main(int argc,char *argv[])
{//定义文件流指针FILE*fpsrc;//定义接收用char recvbuff[20];//定义用于接收返回值char*p=NULL;if(argc!=2){printf("查看格式错误!\n");return -1;}//打开源文件,源文件必须存在fpsrc=fopen(argv[1],"r");if(fpsrc==NULL){printf("源文件打开失败!\n");return -1;}while(1){//从源文件中读内容到数组中p=fgets(recvbuff,20,fpsrc);//当有错误或者读到末尾返回if(p==NULL||feof(fpsrc)==!0)break;//将读到的内容放到目标文件fputs(recvbuff,stdout);}fclose(fpsrc);return 0;
}

3.构造一个学员信息的结构体,包含 姓名 学号 成绩 等成员;编写函数,通过键盘输入3个学员的信息并格把所有信息和学员总数格式化存入文件;---学员总数占一行  每个学生信息占一行然后从文件中读取每个学员的信息并打印

/*构造一个学员信息的结构体,包含 姓名 学号 成绩 等成员;编写函数,通过键盘输入3个学员的信息并格把所有信息和学员总数格式化存入文件;---学员总数占一行  每个学生信息占一行然后从文件中读取每个学员的信息并打印*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct ST
{int num;float socer;char name[20];
}STU;int main()
{STU stu[3];FILE*fp;int num=0;fp=fopen("./1.txt","w+");if(fp==NULL){printf("open error\n");return -1;}//先存入学生总数fprintf(fp,"%d\n",3);//键盘得到信息并存入结构图题中for(int i=0;i<3;i++){printf("请输入第%d个学生的姓名",i+1);scanf("%s",stu[i].name);printf("请输入第%d个学生的学号,成绩",i+1);scanf("%d %f",&stu[i].num,&stu[i].socer);//向1.txt中存入信息fprintf(fp,"%s\t%d\t%f\n",stu[i].name,stu[i].num,stu[i].socer);}//关闭文件fclose(fp);//重新打开文件,使文件指针回到文件开始处fp=fopen("./1.txt","r");if(fp==NULL){printf("open error\n");return -1;}//清空结构体内容memset(stu,0,sizeof(STU)*3);//读取信息fscanf(fp,"%d\n",&num);//将1.txt中的文件输入到numprintf("num=%d\n",num);for(int i=0;i<num;i++){fscanf(fp,"%s\t%d\t%f\n",stu[i].name,&stu[i].num,&stu[i].socer);//将1.txt中的文件输入到结构体printf("姓名%s,学号%d,成绩%f\n",stu[i].name,stu[i].num,stu[i].socer);}return 0;
}

四、文件IO函数

4.1 opendir打开目录

头文件:#include<sys/types.h> #include<dirent.h>
函数原型:DIR * opendir(const char * name);
函数参数:const char * name :   带路径的目录名    "/home"
函数返回值:成功则返回 DIR* 型态的目录流,打开失败则返回 NULL
函数功能:打开一个已存在的目录
函数特性: 目录打开后成功后,目录指针在目录开始处

4.2 closedir 关闭目录

头文件:#include<sys/types.h> #include<dirent.h>
函数原型:int closedir(DIR *dir);
函数参数:DIR *dir  : 目录流指针
函数返回值:
关闭成功则返回 0,失败返回-1
函数功能  关闭一个已存在的目录

4.3 readdir 读目录

头文件:#include<sys/types.h> #include<dirent.h>
函数原型:struct dirent * readdir(DIR * dir);
函数参数:DIR *dir  : 目录流指针
函数返回值 : struct dirent *   结构体指针

  {

      ino_t d_ino                       ; //文件 inode 号

      ff_t d_off                          ; //目录中的偏移

      signed short int d_reclen ; //整条记录的字节长度

      unsigned char d_type      ; //文件类型

      har d_name[256]             ;  //  文件名

  };
函数功能:  读取opendir目录下的一个信息内容 (目录下存在 文件、子目录)
---注意: 信息指的是文件的信息,不是文件内部的内容(要通过open read )
函数特性:读取一次后,目录指针偏移到下一个内容

比如  opendir 打开的目录下存在
1.txt  2.txt  3.txt
这时readdir  首先读取  1.txt  ,再次调用readdir 读取 2.txt  以此类推

4.4 chdir 改变当前工作目录

头文件:#include<unistd.h>
函数原型:int chdir(const char * path);
函数参数:const char * path  新的目录  作为当前工作目录
函数返回值:执行成功则返回 0,失败返回-1
函数功能:改变当前工作目录

4.5 getcwd 获取当前工作目录

头文件:#include<unistd.h>
函数原型:char * getcwd(char * buf,size_t size);
函数参数:
@param1 
char * buf: 以绝对路径方式存在当前工作目录
   @param2 size_t size :  buf的字节数
函数返回值 :执行成功则将结果复制到参数 buf 所指的内存空间,或是返回自动配置的字符串指针。失败返回 NULL,错误代码存于 errno。
函数功能:   得到当前工作目录

五、目录IO练习

编写一个函数,读取指定目录下的信息,只输出信息的名称;然后改变当前工作目录为/bin ,再次读取当前工作目录下的信息并显示

/*编写一个函数,读取指定目录下的信息,只输出信息的名称;然后改变当前工作目录为/bin ,再次读取当前工作目录下的信息并显示*/#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>//定义一个打印函数用于打印目录名称
void printf_dir_contents(const char *path)
{DIR*dir=opendir(path);//打开路径所指的目录if(!dir)//打不开目录,进入分支{fprintf(stderr,"无法打开目录'%s':%s\n",path,strerror(errno));return;}printf("目录'%s'内容:\n",path);//定义一个结构体struct dirent *entry;while((entry=readdir(dir))!=NULL){if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0)// 忽略目录.,..continue;printf("  - %s\n", entry->d_name);//其余的目录则打印输出}closedir(dir);
}//定义函数,读取指定目录,切换到/bin后再读取
void list_and_switch(const char* target_dir)
{char cwd[1024];//1.获取当前工作目录的绝对路径,并将路径打印if(getcwd(cwd,sizeof(cwd)))printf("当前工作目录:%s\n",cwd);elseperror("获取当前目录失败\n");//2.打印当前目录内容printf_dir_contents(cwd);//3.读取指定目录内容printf_dir_contents(target_dir);//4.切换到/bin目录if(chdir("/bin")==-1){perror("切换目录失败");return;}//5.获取并打印当前工作目录if(getcwd(cwd,sizeof(cwd)))printf("切换到目录:%s\n",cwd);elseperror("获取新目录失败\n");//6.读取/bin文件内容printf_dir_contents(".");}
int main() {// 示例:读取 /etc 目录后切换到 /binlist_and_switch("/etc");return 0;
}

http://www.xdnf.cn/news/1471339.html

相关文章:

  • DPO算法
  • C++中虚函数与构造/析构函数的深度解析
  • 标注格式转换csv转xml
  • 【Hot100】回溯
  • 遇到“指责型人格”别硬碰硬!3个反拿捏技巧,让他从挑刺变闭嘴
  • 【前端教程】JavaScript DOM 操作实战案例详解
  • javafx笔记
  • 有序数组,距离目标最近的k个数 二分查找
  • 2025 年高教社杯全国大学生数学建模竞赛C 题 NIPT 的时点选择与胎儿的异常判定详解(一)
  • 数据库基础知识——聚合函数、分组查询
  • ResNet 迁移学习---加速深度学习模型训练
  • 瑞芯微RV1126目标识别算法Yolov8的部署应用
  • 关于kubernetes和docker版本的一些总结
  • 工业设备管理软件与AI_HawkEye智能运维平台_璞华大数据
  • 自定义格式化数据(BYOFD)(81)
  • Python快速入门专业版(五):从 print 到交互:Python 解释器与 IDLE 的基础使用
  • 如何在序列水平上简单分析一个新蛋白质序列(novel protein sequence)
  • AM J BOT | 黄芪稳健骨架树构建
  • 360° 拖动旋转的角度计算原理
  • LangChain: Memory
  • 嵌入式学习日记(41)串口
  • 数据库(基础操作)
  • 载流子寿命
  • 基于FPGA实现CRC校验码算法(以MODBUS中校验码要求为例)verilog代码+仿真验证
  • Python命令行选项(flags)解析
  • 漫画布局面板设计系统
  • 事务管理的选择:为何 @Transactional 并非万能,TransactionTemplate 更值得信赖
  • 从Java全栈到前端框架:一位程序员的实战之路
  • NestJS 整合 Redis 特性详解
  • 2025年统计与数据分析领域专业认证发展指南