文件IO(Ubuntu)

news2024/9/20 21:50:48
  • 文件IO

    • 目的

      • 将数据写入文件中

    • 与标准IO的区别 (为什么要学习文件IO)

      • 标准IO只能操作普通文件和特殊的管道文件

      • 文件IO能操作几乎所有的的文件

      • 缓存区的目的

        • 标准IO有缓存区

        • 文件IO没有缓存区

        • 根据右图描述

          • 标准IO = 文件IO + buffer缓存区

          • 有缓存区的标准IO运行效率更高

          • 没有缓存区的的文件IO实时性更高

      • 系统调用

        • 系统提供给用户的,让用户能够使用底层函数的接口。

        • 因为用户并不能直接调用这些个底层函数,必须通过所谓的"系统调用"这些函数才能调用到底层的函数

        • 既然printf最终调用write,为什么我们只把write称为系统调,不直接把printf称为系统调用呢?

          • printf在不同的系统中,调用的函数是不一样的

            • 在unix系统中,printf调用的就是write

            • 在windows,调用的就是XXXwrite函数了

      • 来源不同

        • 标准IO

          • 来自c语言的标准库,可以移植到任何支持c语言的系统环境中

        • 文件IO

          • 来自UNIX内核提供的库函数

      • 句柄不同

        • 标准IO

          • 使用的是FILE *流指针来描述文件

        • 文件IO

          • 使用的是int类型,我们称为文件描述符,来描述文件

            • 注意:int类型的文件描述符才是真正描述文件地址的一个变量

          • 问题:明明是int类型,怎么去描述文件地址

            • stdin,stdout,stderr

              • 三个流文件(默认文件)

            • void* filearr[n] = {&stdin,&stdout,&stderr}

              • filearr这个文件指针数组中,默认的存放了3个文件的地址,终端输入文件地址,终端输出文件地址,终端错误文件地址

              • “标准输入流文件”的地址,被存放在数组中的第0个下标上

              • “标准输出流文件”的地址,被存放在数组中的第1个下标上

              • “标准错误流文件”的地址,被存放在数组中的第2个下标上

              • 所以,我们只要给"系统调用"提供下标信息,系统调用函数就会根据下标信息找到对应的文件指针

            • 所以我们把文件在数组中的int类型的下标信息,称为这个文件的描述符

    • 如果获得int类型的描述符

      • open函数

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

        • 功能描述

          • 打开pathname文件,如何打开由flags决定 (比如创建,清空,可读可写等属性)。 如果文件需要创建的话,创建权限值由mode决定

        • 参数1

          • 指定被打开的文件的路径名

        • 参数2

          • 打开时文件的属性

            • O_RDONLY

              • 文件以只读的形式打开

            • O_WRONLY

              • 文件以只写的形式打开

            • O_RDWR

              • 文件以读写的形式打开

            • O_APPEND

              • 文件以追加的形式打开

            • O_CREAT

              • 如果文件不存在,则创建文件打开

            • O_EXCL

              • 若文件存在则打开失败,配合O_CREAT使用

              • 实现效果:若文件不存在则创建文件, 如果存在则什么都不发生

            • O_NONBLOCK

              • 以非阻塞的形式打开文件

            • O_TRUNC

              • 若文件存在则清空文件打开

              • 即fopen的第二个参数如果写“w”,那么打开文件为只写打开,如果文件不存在则创建文件,如果文件存在则清空文件后打开

              • 也就是说fopen的第二个参数“w” = open的第二个参数传:O_WRONLY | O_CREAT | O_TUNC

        • 参数3

          • 当第二个参数flags里面拥有O_CREAT属性的时候,此时要求传入第3个参数mode,用来表示文案创建时候的权限,故一般传0664,0666这样的数据

          • 创建文件时未传入权限值,则会以一个随机的权限创建文件

        • 返回值

          • 成功打开文件,返回该值的描述符(int类型)

          • 失败返回-1

          • open函数返回的文件描述符的取值规则为:最小未使用位置 例:原本打开文件为 0 1 2 3 4 5 此时关闭3号文件,那么描述符就为 : 0 1 2 4 5 此时,若我们又打开了一个新文件,那么描述符就有:012345

        • 不使用文件时关闭文件

          • close(fd)

    • 文件IO的输入输出函数

      • write

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

        • 参数1

          • 文件描述符

        • 参数2

          • 存放有准备写入文件中的数据的地址

        • 参数3

          • 准备写入的数据的数量

          • 注意

            • 该函数是一个数据流函数(字符)

        • 返回值

          • 成功写入数据,返回写入数据的数量

          • 失败返回-1

            • 失败原因:只可能是描述符突然关闭

        • 阻塞型函数

          • 将输入写入的数据,若存满,则会阻塞 直到文件出现空闲内存为止

      • read

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

        • 功能描述

          • 将fd描述的文件中,最多读取count个字节的数据,然后写入buf中

        • 参数1

          • 文件描述符号

        • 参数2

          • 存放读取到的数据的地址

        • 参数3

          • 最多读取的数据的数量

        • 注意

          • 根据文件描述符的不同,read的行为模式不同,有阻塞的也有非阻塞的

          • 描述符

            • 描述普通文件时:read非阻塞

            • 描述终端时:read阻塞

            • 描述管道文件时:read阻塞

            • 描述套接字时:read阻塞

        • 返回值

          • 成功返回读取到的数据的数量

          • 失败返回-1

          • 没有读取到数据返回0

          • read实际上根据描述符的文件的不同,行为模式的不同,返回值的意义都是不同的

        • 注意

          • fread只要读取到文件结束符就会返回0 而read读取到文件结束符不会返回0 只有read读取一次之后发现没有读取到数据才会返回0

    • 3个特殊文件描述符

      • 标准输入流

        • STDIN_FILENO 或 0

      • 标准输出流

        • STDOUT_FILENO 或 1

      • 标准错误流

        • STDERR_FILENO 或 2

    • 重定向函数

      • dup2

        • int dup2 = (int oldfd, int newfd);

        • 目标:将标准错误流 STDERR_FILENO, 重定向到err.txt这个文件中

          • dup2(err.txt, STDERR_FILENO);

          • 解析:

            • filearr[n] = {&stdin, &stdout, &stderr};

            • 代码int fd = open("./err.txt", ...);执行后filearr将会在最小未使用位置上放置打开的文件

            • filearr[n] = {&stdin, &stdout, &stderr, &err.xtxt};

            • 当执行代码dup2(err.txt, STDERR_FILENO);

              • 本质上相当于执行 filarr[STDERR_FILENO] = filearr[fd] (同等于filarr[2] = filearr[3])

            • filearr更新为filearr[n] = {&stdin, &stdout, &err.txt, &err.txt}

              • 此时&stderr被覆盖

            • perror()函数默认调用STDERR_FILEENO

              • 此时2位置上的文件为err.txt实现了错误信息输出到自定文件中

      • dup

        • int dup(int older);

        • 功能描述

          • 将odler,在filearr中的最小未使用位置上,做备份,被返回该位置的值,作为描述符

          • 原本:filearr[n] = {&stdin, &stdout, &stderr};

          • 执行:dup(STDERR_FILENO);

          • 更新后:filearr[n] = {&stdin, &stdout, &stderr, &stderr};(dup 返回3)

            • 当文件2被覆盖后执行dup2(3, STDERR_FILEENO)

            • 即可恢复标准错误流的指向

    • 判断文件是否存在,是否拥有用户可读可写可执行权限

      • 功能描述

        • 判断pathname文件是否拥有mode权限

      • access

        • int access(const char *pathname, int mode);

        • 功能描述

          • 判断pathname文件,是否拥有mode权限

        • 参数 pathname

          • 准备判断的文件路径名

        • 参数 mode

          • F_OK

            • 判断文件是否存在

          • R_OK

            • 判断文件是否拥有用户可读权限

          • W_OK

            • 判断文件是否拥有用户可写权限

          • X_OK

            • 判断文件是否拥有用户可执行权限

        • 返回值

          • 成功判断返回0,失败返回-1

    • 判断文件的类型以及文件是否拥有UGO的3项权限

      • stat,fstat,lstat

        • stat

          • int stat(const char *pathname, struct stat *statbuf);

        • fstat

          • int fstat(int fd, struct stat *statbuf);

        • lstat

          • int lstat(const char *pathname, struct stat *statbuf);

        • 以上3个函数全都是用来判断文件类型或者判断文件是否拥有某项权限的

          • 区别在于:

          • stat和fstat

            • 一个使用文件路径名锁定文件,一个使用文件描述符锁定文件

          • stat和lstat

            • 他俩只有在判断符号链接文件的时候才有区别

          • 当符号链接文件传递给stat的时候,stat会获取到符号链接文件所引用的源文件的属性和类型

          • 当符号链接文件传递给lstat的时候,无论符号连接文件引用的源文件是什么类型,获取到的都是符号连接文件本身的属性和文件

        • 参数 pathname

          • 准备获取属性和类型的文件的路径名

        • 参数 statbuf

          • 用来存放获取到的文件的属性和类型的地址,文件有哪些属性,类型怎么判断。 详见statbuf,结构体如下

        • struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* Inode number */ mode_t st_mode; /* File type and mode */ nlink_t st_nlink; /* Number of hard links */ uid_t st_uid; /* User ID of owner */ gid_t st_gid; /* Group ID of owner */ dev_t st_rdev; /* Device ID (if special file) */ off_t st_size; /* Total size, in bytes */ blksize_t st_blksize; /* Block size for filesystem I/O */ blkcnt_t st_blocks; /* Number of 512B blocks allocated */ }; 注释说的很明确,文件类型和属性,都在st_mode里面放着

      • 如果通过stat函数判断一个文件是否拥有某项权限

        • 根据 :一个数 | 另一个数 如果没有发生改变的话,则表明该数拥有被按位或的数

          • 权限的宏定义如下 S_ISUID 04000 set-user-ID bit S_ISGID 02000 set-group-ID bit (see below) S_ISVTX 01000 sticky bit (see below) S_IRWXU 00700 owner has read, write, and execute permission S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 group has read, write, and execute permission S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 others (not in group) have read, write, and execute permission S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permission S_IXOTH 00001 others have execute permission

      • 如何判断一个文件的类型

        • 使用以下几个带参宏,来判断文件的类型

          • S_ISREG(st_mode) is it a regular file?

          • S_ISDIR(st_mode) directory?

          • S_ISCHR(st_mode) character device?

          • S_ISBLK(st_mode) block device?

          • S_ISFIFO(st_mode) FIFO (named pipe)?

          • S_ISLNK(st_mode) symbolic link? (Not in POSIX.1-1996.)

          • S_ISSOCK(st_mode) socket? (Not in POSIX.1-1996.)

        • 只要将st_mode 传入一下几个带参宏里面,就能得到结果

        • 比如说:如果是一个普通文件,那么只哟 S_ISREG(st_mode) 返回1,其他所有带参宏返回0

    • 设置掩码的函数

      • 什么叫做掩码:和文件权限相关一个数据 顾名思义:就是需要遮掩掉某些值的一个码 其实,我们在创建文件时候,我们所指定的权限值,并不是这个文件的最终权限值,而是需要剔除掉掩码当中所设定的哪些权限后,才是文件的最终权限值

        • 如果当前掩码为 0111

          • 文件创建权限为 0666,文件最终权限是 0666

        • 如果当前掩码设置为 0333

          • 文件创建权限为 0666 ,文件最终权限为 0444

        • 当前掩码设置的是 0111

          • 如果,文件创建的时候,创建权限为 0777 ,所以文件最终权限需要扣除掩码的权限,最终权限为 0666

      • mode_t umask(mode_t cmask);

        • 功能描述:设置当前程序掩码的值

        • 参数 cmask:掩码值

作业: 实现目录下所有文件的复制 

#include <myhead.h>
#include <dirent.h>

int main(int argc, const char *argv[])
{
	//首先判断目标文件夹是否存在
//	if(access("./a", F_OK) == -1)
//	{

//	}
	//打开a目录
	struct dirent *dir;
	DIR *dirp = opendir("./a");
	if(NULL == dirp)
	{
		perror("opendir");
		return -1;
	}
	
	int ret = 0;
	while(NULL != (dir = readdir(dirp)))
	{
/*		char tar_path[32] = {0};
		strcat(tar_path, "/");
		char org_path[32] = {0};
		strcat(org_path, "/");
		strcat(tar_path, dir -> d_name);
*/		
		if(strcmp(dir -> d_name, ".") == 0 || strcmp(dir -> d_name, "..") == 0){continue;}

		chdir("./a");
		int rfd = open(dir -> d_name, O_RDONLY);
		chdir("..");

		chdir("./b");
		int wfd = open(dir -> d_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
	
		while(1){
		char arr[3] = {0};

		ret = read(rfd, arr, 3);
		if(ret <= 0){break;}
		write(wfd, arr, ret);

		}
		chdir("..");
		close(rfd);
		close(wfd);
	}
	closedir(dirp);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1940310.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++基础(类和对象中)(类的默认成员函数)

目录 一.构造函数&#xff08;类似初始化&#xff09; 1.概念 2.构造函数的特点 二.析构函数&#xff08;类似 销毁对象/空间&#xff09; 三.拷贝构造函数(类似复制粘贴的一种 初始化 ) 1.概念&#xff1a; 2.拷贝构造的特点&#xff1a; 四.赋值运算符重载&#xff08…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(四)-无人机认证与授权

引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 【免费】3GPPTS23.256技术报告-无人机系…

Linux系统之快速部署小游戏合集网站(二)

Linux系统之快速部署小游戏合集网站(二) 一、项目介绍1.1 项目简介1.2 项目预览二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍三、检查本地环境3.1 检查系统版本3.2 检查系统内核版本3.3 检查软件源四、安装Apache24.1 安装Apache2软件4.2 启动apache2服务4.3 查看apach…

Leetcode3211. 生成不含相邻零的二进制字符串

Every day a Leetcode 题目来源&#xff1a;3211. 生成不含相邻零的二进制字符串 解法1&#xff1a;回溯 可以使用回溯得到所有长度为 n 的有效字符串。 字符串的每个位置都需要填入 0 或 1。对于 0≤i<n&#xff0c;如果 i0 或字符串的下标 i−1 处填入 1&#xff0c;则…

python一维表转二维表

一维表转二维表 import pandas as pd # 读取数据 product_df pd.read_csv(rD:\excelFile\practice\物品属性值一维表.csv,encodingutf-8) # print(product_df)# 将一维表转变二维 s pd.Series(list(product_df[属性值]),index[product_df[物品编号],product_df[属性名]]) …

Langchain[6]-LangGraph:异步和流、图可视化、多智能体协作、LCEL代码生成

Langchain[6]-LangGraph:异步和流、图可视化、多智能体协作、LCEL代码生成 1.异步和流 因为任何大模型在推理的时候,都会有一定的时间延迟,这是由大模型的底层架构决定的,所以在很多应用,尤其是对话应用中,使用异步以及流式输出,是大幅提升用户体验的较好方法。 在langG…

产品经理-​统计数据是如何产生的(20)

在互联网当中,监测一个项目的实际情况,在产品当中,往往需要进行数据的监测,看用户的习惯,进而进行对产品进行优化,比如统计产品用户的一些行为,鼠标点击,鼠标hover,停留时长,进入,进出等 产品经理看到的数据统计一般是经历了下面几个阶段 数据埋点&#xff1a;这个阶段产品经理…

Leetcode215. 数组中的第K个最大元素

我们也可以使用堆排序来解决这个问题——建立一个小根堆&#xff0c; 遍历数组将元素入堆&#xff1b;如果当前堆内元素超过 k 了&#xff0c;我们就把堆顶元素去除&#xff0c;即去除当前的最小值。因此我们在元素入堆的过程中&#xff0c;不断淘汰最小值&#xff0c;最终留在…

《从C/C++到Java入门指南》- 7.浮点数运算

浮点数运算 引言 浮点数在计算机中难以进行精确表示&#xff0c;例如&#xff1a;0.1 换算成二进制是一个无限循环的小数&#xff0c;无论是double 还是float&#xff0c;都只能存储一个近似的值。但是0.5却可以进行精确的表示。 误差 浮点数的运算时常伴有误差&#xff1a…

RHCE(免密登录+web服务器)之小试牛刀

1、配置linux客户端免密登录服务端linux主机的root用户 2、配置web服务器&#xff0c;当访问网站www.haha.com时显示&#xff1a;haha 3、配置web服务器&#xff0c;当访问网站www.xixi.com/secret/显示&#xff1a;this is secret 本实验使用RHEL9.3和Rocky linux8操作系统 RH…

AI赋能下的人体摔倒识别技术:深度解析与应用前景

引言 随着人工智能技术的快速发展&#xff0c;AI赋能的解决方案在各行各业中展现出巨大的潜力。特别是在安全监控和健康护理领域&#xff0c;AI技术的应用不仅提高了效率&#xff0c;还极大地提升了安全性。本文将深入探讨思通数科&#xff08;南京&#xff09;信息技术有限公…

ipv6 基础学习(一)

IPv6 为什么要有IPV6&#xff1f; IPv4地址空间有限&#xff1a;IPv4使用32位地址&#xff0c;最多可提供约43亿个地址。随着互联网设备数量的爆炸式增长&#xff0c;这些地址已经几乎耗尽。 IPv6地址空间庞大&#xff1a;IPv6使用128位地址&#xff0c;可以提供大约3.410^3…

人工智能与机器学习原理精解【2】

文章目录 机器学习基础一般化流程回归线性回归一元线性回归基础斜率的公式克莱姆法则&#xff08;Cramers Rule&#xff09;一、克莱姆法则的基本内容二、克莱姆法则的适用条件三、克莱姆法则的优缺点四、总结 导数与极值的问题 julia实现 最小二乘法原理最小二乘法的原理线性回…

视觉巡线小车——STM32+OpenMV

系列文章目录 第一章&#xff1a;视觉巡线小车——STM32OpenMV&#xff08;一&#xff09; 第二章&#xff1a;视觉巡线小车——STM32OpenMV&#xff08;二&#xff09; 第三章&#xff1a;视觉巡线小车——STM32OpenMV&#xff08;三&#xff09; 第四章&#xff1a;视觉巡…

前端打印如何给打印页加上水印

插件使用相关&#xff1a;vue-print-nb 前端打印的一个实现方案-CSDN博客 示例代码&#xff1a; media print {page {size: auto; //页面大小自动&#xff0c;防止打印版不全margin: 15mm; //页面边距的设定}body{background-image: url(/assets/images/login/logo.png);back…

java高级——Collection集合之Set探索(底层为HashMap实现)

java高级——Collection集合之Set探索 前情提要文章介绍继承结构底层代码&#xff08;一张图你就悟了&#xff09;下期预告 前情提要 上一篇文章我们探索了HashMap&#xff0c;详细解说了哈希冲突&#xff0c;红黑树以及Map底层到底是怎么实现的&#xff0c;这一篇我们简单说一…

三字棋游戏(C语言详细解释)

hello&#xff0c;小伙伴们大家好&#xff0c;算是失踪人口回归了哈&#xff0c;主要原因是期末考试完学校组织实训&#xff0c;做了俄罗斯方块&#xff0c;后续也会更新&#xff0c;不过今天先从简单的三字棋说起 话不多说&#xff0c;开始今天的内容 一、大体思路 我们都知…

开源模型应用落地-FastAPI-助力模型交互-进阶篇-RequestDataclasses(三)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

Springcloud之gateway的使用详解

官网地址&#xff1a;https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/ 1.网关入门 helloword 网关不依赖start-web 导入的pom&#xff1a; <!--gateway--> <dependency><groupIdorg.springframework.cloud</groupId><arti…

CKS-Kubernetes-证书题库总结

证书如下 个人考试总结 第一次考试 成绩如下&#xff0c;其实这一次我题目全做了&#xff0c;个人感觉也没有什么错误&#xff0c;但是环境做错了 7月14日CKS考试笔记 问题分析 你这次考试得了57%。 至少需要67%的分数才能通过。 对您完成的考试的自动分析显示了三个得分最…