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

华清远见25072班I/O学习day2

重点内容:

模块化读写(fread/fwrite)

        size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

        功能:从stream指向的文件中读取nmemb项数据,每一项的大小为size 并且放入ptr指向的容器中

        参数1:存放数据的容器,可以是任意类型的指针

        参数2:每一项的大小

        参数3:读取的总项数

        参数4:文件指针

        返回值:成功返回读取的项数,失败或者文件结束返回一个小于项数的值         

        注意:fread不区分到底是因为文件结束还是因为错误导致的结束,可以使用feof和ferror来判断

        size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

        功能:将ptr指向的容器中的内容,每项为size大小的nmemb项数据,写入到stream指向的文件中

        参数1:要写入的数据起始地址

        参数2:每一项的大小

        参数3:要写入的项数

        参数4:文件指针

        返回值:成功返回写入的项数,失败或者文件结束返回一个小于项数的值

有关文件指针光标的操作(fseek/ftell/rewind)

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

        功能:将给定的文件指针的光标进行重新定位

        参数1:文件指针

        参数2:偏移量(以字节为单位) >0:表示从给定的基准向后偏移 =0:表示在基准处不偏移 <0:从基准处向前偏移

        参数3:基准 SEEK_SET:文件开始位置 SEEK_CUR:光标当前位置 SEEK_END:文件结尾位置

        返回值:成功返回0,失败返回-1并置位错误码

        long ftell(FILE *stream);

        功能:求出现在文件指针光标所在位置(以字节为单位)

        参数:文件指针

        返回值:光标目前所在位置

eg:求一个文件的大小 1、将光标先定位到结尾:fseek(fp, 0, SEEK_END); 2、此时使用ftell的返回值,就是文件的大小:ftell(fp);

        void rewind(FILE *stream);

         功能:将文件光标定位到开始位置             等同于:fseek(fp, 0, SEEK_SET);

        参数:文件指针

        返回值:无

有关缓冲区的问题

        1.对于标准IO而言,分为三种缓冲区:

                全缓存、行缓存、不缓存

        2.全缓存:对应的是用户打开的文件指针:fp 其大小为4096字节

        行缓存:对应的是stdin和stdout,其大小为1024字节

        无缓冲:对应的是stderr,其大小为0字节

        3.缓冲区的刷新时机

                1、行缓存

                        1、遇到\n会刷新

                        2、当使用fflush刷新时,会刷新缓冲区

                        3、当程序结束时会刷新缓冲区

                        4、当使用exit退出进程时,会刷新标准io缓冲区

                        5、当输入输出发生切换时会刷新缓冲区

                        6、当缓冲区满了后,再向缓冲区中放数据时,会刷新该缓冲区

                2、全缓存

                        1、当使用fflush刷新时,会刷新缓冲区

                        2、当程序结束时会刷新缓冲区

                        3、当使用exit退出进程时,会刷新标准io缓冲区

                        4、当输入输出发生切换时会刷新缓冲区

                        5、当缓冲区满了后,再向缓冲区中放数据时,会刷新该缓冲区

                3、没有条件,放入立即刷新

有关错误码的问题

        1.错误码是调用内核提供的函数时,如果调用出错,那么内核空间会向用户空间反馈一个错误信息

        2.错误信息千奇百怪,并且是字符串内容,为了方便起见,给这些错误信息,进行编号

        3.如果,内核空间函数调用出问题时,只需要反馈错误编号即可,这个错误编号就叫做错误码

        4.常见错误码:可以通过指令 vi -t EIO 查看

文件IO:

        文件IO是指用户直接调用内核提供的函数来进行IO操作,但是标准IO使用的是文件指针完成,文件IO使用的是文件描述符来实现

文件描述符

        1.文件描述符是内核用来跟外部文件设备操作的一个非负整数

        2.每一个文件描述符对应一个操作的文件

        3.当一个程序启动后,系统默认打开三个特殊的文件描述符,分别是0号(标准输入stdin)、1号(标准输出)和2号(标准出错)

        4.文件描述符的分配原则是:最小未使用原则

        5.默认情况下,一个进程能够打开的文件描述符的个数为1024个,也就是0--1023

打开文件open

        int open(const char *pathname, int flags);

        int open(const char *pathname, int flags, mode_t mode);

        功能:使用系统调用,打开给定pathname对应的文件,并返回该文件对应的文件描述符

        参数1:要被打开的文件

        参数2:打开模式

                1、必须包含以下三个中的一个

                        O_RDONLY: 只读的形式打开文件

                        O_WRONLY:只写的形式打开文件

                        O_RDWR:读写的形式打开文件

                2、下面的可以包含也可以不包含,根据需要而定,所有标识通过位或连接

                        O_CREAT:如果文件不存在,则创建文件,注意,如果参数2中包含该标识, 则必须提供参数3,为文件的操作权限

                        O_TRUNC:清空文件内容

                        O_APPEND:追加形式

                        O_EXCL:确保创建新文件成功,如果文件已经存在,则报错,错误码为EEXIST

        参数3:文件操作权限。注意:最终的文件权限,是由给定的权限跟默认掩码取反后取位与运算得到

        运算:mode & (~umask)                 umak取决于终端

        一般情况下:文件夹的权限最大为:0775 普通文件的权限:0664

        返回值:成功返回打开的文件对应的文件描述符(最小未分配原则),失败返回-1并置位错误码

        标准IO打开文件模式对应的操作位

关闭文件close

        int close(int fd);

        功能:关闭指定的文件描述符

        参数:文件描述符

        返回值:成功返回0,失败返回-1并置位错误码

数据读写(read、write)

        ssize_t read(int fd, void *buf, size_t count);

        功能:从fd文件描述符中读取count个字节的数据,并存放到buf指向的容器中

        参数1:文件描述符

        参数2:存放数据的容器起始地址

        参数3:要读取数据的大小

        返回值:成功返回读取的字节个数,失败返回-1并置位错误码

        ssize_t write(int fd, const void *buf, size_t count);

        功能:向fd文件描述符标识的文件中写入以buf作为起始地址的count个数据

        参数1:文件描述符

        参数2:要写入数据的容器起始地址

        参数3:要写入数据的大小

        返回值:成功返回写入的字节个数,失败返回-1并置位错误码

光标偏移(lseek)

        off_t lseek(int fd, off_t offset, int whence);

        功能:偏移fd文件描述符的光标

        参数1:文件描述符

        参数2:偏移量(以字节为单位)

                >0:表示从给定的基准向后偏移

                =0:表示在基准处不偏移

                <0:从基准处向前偏移

        参数3:基准

                SEEK_SET:文件开始位置

                SEEK_CUR:光标当前位置

                SEEK_END:文件结尾位置

        返回值:成功返回光标当前位置,失败返回(off_t)-1并置位错误码


作业:

1> 使用fread、fwrite实现两个文件的拷贝

程序源码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
FILE *fp=NULL;
FILE *fp1=NULL;
//从文件中读取数据
if((fp = fopen("./wcg.txt", "r")) == NULL)
{
printf("文件打开失败\n");
return -1;
}
if((fp1 = fopen("./wcgcope.txt", "w")) == NULL)
{
printf("文件打开失败\n");
return -1;
}
//将文件中的数据读取出来
char buf[128] = "";
while(1)
{
int res = fread(buf, 1, sizeof(buf), fp);
if(res < 128)
{
//判断是因为文件结束还是因为错误
if(feof(fp))
{
//printf("buf=%s\n", buf);
//将读取的数据全部写到新的文件中
fwrite(buf, res, 1, fp1);
break;           //因为文件结束
}
if(ferror(fp))
{
printf("fread操作失败\n");
return -1;
}
}
//将读取的数据写到新的文件中
fwrite(buf, res, 1, fp1);
}
//关闭文件
fclose(fp);
fclose(fp1);
return 0;
}

2> 使用fread、fwrite实现将一个文件中的所有数字写入到另一个新文件中

程序源码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//定义函数用于筛选数字
void num(char *p,char *q,int len)
{
int j=0;
for(int i=0;i<len;i++)
{
if(p[i]>='0'&&p[i]<='9')
{
q[j++]=p[i];
}
}
q[j]='\0';
}
int main(int argc, const char *argv[])
{
FILE *fp=NULL;
FILE *fp1=NULL;
//从文件中读取数据
if((fp = fopen("./wcg.txt", "r")) == NULL)
{
printf("文件打开失败\n");
return -1;
}
if((fp1 = fopen("./wcgcope1.txt", "w")) == NULL)
{
printf("文件打开失败\n");
return -1;
}
//将文件中的数据读取出来
char buf[128] = "";
while(1)
{
char arr[128]="";
int res = fread(buf, 1, sizeof(buf), fp);
if(res < 128)
{
//判断是因为文件结束还是因为错误
if(feof(fp))
{
//将读取的数据全部写到新的文件中
num(buf,arr,res);
fwrite(arr,1,strlen(arr),fp1);
break;           //因为文件结束
}
if(ferror(fp))
{
printf("fread操作失败\n");
return -1;
}
}
//将读取的数据写到新的文件中
num(buf,arr,res);
fwrite(arr,1,strlen(arr),fp1);
}
//关闭文件
fclose(fp);
fclose(fp1);
return 0;
}

3> 使用文件IO完成两个文件的拷贝

程序源码:

#include <25072head.h>
int main(int argc, const char *argv[])
{
//1、创建并打开一个文件
int fd = -1;
if((fd = open("./tt.txt", O_RDWR|O_CREAT|O_TRUNC, 0664)) == -1)
{
perror("open error");
return -1;
}
int fd1=-1;
if((fd1 = open("./ttcope.txt", O_RDWR|O_CREAT|O_TRUNC, 0664)) == -1)
{
perror("open error");
return -1;
}

    printf("fd = %d\n", fd);         
//向文件中写入数据
char buf[128] = "";
while(1)
{
//从终端获取数据
int res = read(0, buf, sizeof(buf));
if(res == 1)
{
break;
}
//将数据写入到fd指向的文件中
write(fd, buf, res);
}
//从文件中读取数据
lseek(fd,0,SEEK_SET);
char rbuf[128] = "";
int res = read(fd, rbuf, sizeof(rbuf));     //从文件中读数据
//将数据写到终端上
write(fd1, rbuf, res);
//关闭文件
close(fd);
return 0;
}

4> 自己总结标准IO和文件IO的区别与联系

        标准IO:代码和程序员之间的数据交互        

        文件IO:代码和文件系统之间的数据交互

                1.文件IO没有缓冲区,标准IO函数存在缓冲区

                2.标准IO函数的读取速度快于文件IO函数

                3,标准IO函数本质上就是文件IO的二次封装,标准IO=文件IO+缓冲区

                4.文件IO可以直接和内核交互,标准IO不可以直接和内核交互,标准IO函数只可以访问普通文件,但是文件IO函数可以访问任意的特殊文件(管道,套接字)

                5.文件IO属于系统文件,依赖于操作系统,可以移植性差

                6.标准IO函数属于库文件,可以在不同的操作系统中使用,可移植性强

                7.文件IO遵循POIX标准,标准IO函数满足ANSI标准

                8.文件IO函数操作文件需要借助于文件描述符

                9.标准IO函数操作文件需要借助于流指针

5> 思维导图

6> 牛客网刷题 >= 26

http://www.dtcms.com/a/362192.html

相关文章:

  • PostgreSQL备份指南:逻辑与物理备份详解
  • 椭圆曲线群运算与困难问题
  • 【数据分享】多份土地利用矢量shp数据分享-澳门
  • AI产品经理面试宝典第81天:RAG系统架构演进与面试核心要点解析
  • Qt中的信号与槽机制的主要优点
  • 自动化测试时,chrome浏览器启动后闪退的问题
  • 【趣味阅读】Python 文件头的秘密:从编码声明到 Shebang
  • VisionProC#联合编程相机实战开发
  • 【云存储桶安全】怎么满足业务需求,又最大程度上满足信息安全要求呢?
  • 1792. 最大平均通过率
  • 学习:uniapp全栈微信小程序vue3后台-暂时停更
  • 本地没有公网ip?用cloudflare部署内网穿透服务器,随时随地用自定义域名访问自己应用端口资源
  • 液态神经网络:智能制造的新引擎
  • 【跨境电商】上中下游解释,以宠物行业为例
  • 洛谷 c++ P1177 【模板】排序 题解
  • AutoSar RTE介绍
  • 特征增强方法【特征构建】
  • MVC、三层架构
  • RT-DETR网络结构
  • 并发之线程
  • 【思考】WSL是什么
  • 一、SVN与svnbucket.com常见问题解答
  • 从组分到涌现:系统科学视域下结构、功能与层级的辨析及在人工智能中的应用
  • 设备管理软件正在成为制造业企业的战略重点_HawkEye智能运维平台_璞华大数据
  • 对比Mysql理解OceanBase中的租户设计
  • PostgreSQL 从入门到精通:一场与开源数据库的深度对话
  • 时序数据库国产的有哪些?
  • 利用棒棒糖图探索Office (US)的IMDB评分
  • 毕业项目推荐:64-基于yolov8/yolov5/yolo11的蝴蝶种类检测识别系统(Python+卷积神经网络)
  • 如何修复 Vercel 函数超时并大幅降低云函数成本