【嵌入式Linux】<总览> 文件IO(更新中)

news2024/12/22 15:30:31

文章目录

前言

一、常用函数

1. open函数

2. close函数

3. write函数

4. read函数

5. dup函数

6. dup2函数

二、文件读写细节

1. 换行符

2. 文件描述符

3. errno和perror


前言

在Linux系统中,一切皆文件。因此,掌握Linux下文件IO常用的函数、理解读写文件背后的原理至关重要。在【嵌入式Linux笔记】第三篇:Linux应用开发基础(上)中,本人已经记载了相关的文件IO的知识,但那篇只是用于快速入门,记录的知识并不全面。本篇更加细致地记录文件IO中的重要知识点,若涉及版权问题,请联系本人删除。


一、常用函数

文件IO操作流程:首先调用open函数打开文件,其次采用read/write函数进行读写操作,最后调用close函数关闭文件。

值得注意的是:调用open函数之后,内核就会在进程中建立一个打开文件的数据结构,记录打开的文件;然后内核去磁盘(块设备)中找到文件,将其加载到内存中,我们读写都是作用于内存中的文件;最后调用close函数才会将内存中的文件写入到块设备中。

这样设计的原因:块设备本身有读写限制,读写操作起来不灵活;内存以字节为单位,操作灵活方便。

1. open函数

【1】头文件:#include <sys/types.h>、#include <sys/stat.h>、#include <fcntl.h>

【2】函数原型:

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

【3】功能:打开或创建一个文件

【4】相关描述:

①pathname:指明了文件打开的地址。

②flags:必须包含以下之一:O_RDONLY, O_WRONLY, O_RDWR。当有多个参数时,用|来分隔。其余如下的flags是可选的:

  • O_APPEND:追加内容
  • O_TRUNC:截断,如果文件存在并且以只写、读写方式打开,则将其长度截断为0
  • O_CREAT:若文件不存在,则创建
  • O_EXCL:若要创建的文件已存在,则出错并返回-1,同时修改errno的值
  • O_NONBLOCK:以非阻塞方式打开设备文件
  • O_SYNC:write函数阻塞等待内容全部写入块设备中才返回
  • 注意:如果 O_APPEND | O_TRUNC 则为 O_TRUNC 的效果

③mode:只有当创建新文件时(使用了O_CREAT时)才使用,用于指定文件的访问权限,能用权限的数字表示法。

  • umask能够设置文件在创建时mode的掩码。例如,使用umask命令得到"0002"的结果,那么文件创建时模式掩码为"000 000 000 010"。其实就是other用户权限总数字-2。
  • 使用open创建文件时最终的权限结果为:"mode & ~umask"。因此,若指定权限为0777但创建文件的权限结果为"000 111 111 101"即0775.

④返回值:

  • 打开成功:是一个文件描述符,其是一个小的、非负整数。成功调用返回的文件描述符是当前未为进程打开的编号最低的文件描述符。
  • 打开失败:-1

⑤机制:调用open函数会创建一个新的打开文件描述,打开文件描述记录了文件偏移量和文件状态标志。文件描述符就是对该打开文件描述的参考。当路径名被删除或修改为其它文件,则此参考并不受影响。

【5】open函数打开文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
	//命令检测
	if (argc != 2) {
		printf("请输入命令:%s <filename>\n", argv[0]);
		return -1;
	}
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if (fd < 0) {
		perror("错误信息");
		return -1;
	}
	//执行相关操作
	printf("打开文件成功,fd=%d\n", fd);
	//关闭文件
	close(fd);
	return 0;
}

【6】open函数创建文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
	//命令检测
	if (argc != 2) {
		printf("请输入命令:%s <filename>\n", argv[0]);
		return -1;
	}
	//打开文件,若不存在则创建权限为777
	//但是系统保护,最终创建权限为775
	int fd = open(argv[1], O_RDWR | O_CREAT, 0777);
	if (fd < 0) {
		perror("错误信息");
		return -1;
	}
	//执行相关操作
	printf("打开文件成功,fd=%d\n", fd);
	//关闭文件
	close(fd);
	return 0;
}

2. close函数

【1】头文件:#include <unistd.h>

【2】函数原型:int close(int fd);

【3】功能:关闭文件描述符为fd的文件。

【4】返回值:关闭成功为0,关闭失败为-1


3. write函数

【1】头文件:#include <unistd.h>

【2】函数原型:ssize_t write(int fd, const void *buf, size_t count);

【3】功能:将buf中指定字节数count的内容写入文件描述符为fd的文件中。

【4】相关描述:

  • ①返回值:
    • 写入成功:返回写入的字节数
    • 写入失败:返回小于写入字节数
    • 发生错误:返回-1
  • 使用lseek函数给指定位置写入内容,是对原有位置内容进行覆盖。

【5】示例:命令行中用户输入运行命令时,给出多条字符串,将字符串写入指定文件中。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int argc, char **argv)
{
	/* 1.命令格式判定 */
	if (argc <= 2) {
		printf("请输入命令:%s <文件名> 字符串1 ...\n", argv[0]);
		return -1;
	}
	/* 2.打开文件 */
	int fd = open(argv[1], O_RDWR | O_CREAT, 0664);
	if (fd < 0) {
		perror("打开文件失败");
		return -1;
	}
	/* 3.写入字符串 */
	for (int i = 2; i < argc; ++i) {
		int writeLen = write(fd, argv[i], strlen(argv[i]));
		if (writeLen < strlen(argv[i])) {
			perror("写入失败");
			break;
		}
		write(fd, "\n", 1);//每个字符串后再换行
	}
	/* 4.关闭文件 */
	close(fd);
	return 0;
}

4. read函数

【1】头文件:#include <unistd.h>

【2】函数原型:ssize_t read(int fd, void *buf, size_t count);

【3】功能:将文件描述符为fd的文件中指定字节数count的内容读取到buf中。

【4】返回值:读取成功返回字节数,发生错误返回-1。在判定读取是否成功时,最好不要拿返回的字节数与指定的读取字节数作比较,因为有时指定的字节数会比返回的字节数大。

【5】示例:

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	/* 1.命令格式判定 */
	if (argc != 2) {
		printf("请输入如下格式:%s <文件名>\n", argv[0]);
		return -1;
	}
	/* 2.打开文件:只读 */
	int fd = open(argv[1], O_RDONLY);
	if (fd < 0) {
		perror("打开失败");
		return -1;
	}
	/* 3.读取文件中所有内容 */
	char readBuf[100];
	int readLen = read(fd, readBuf, sizeof(readBuf));
	if (readLen == -1) {
		perror("读取失败");
		close(fd);
		return -1;
	}
	printf("读取的文本长度:%d\n", readLen);
	printf("读取的文本内容:%s", readBuf);
	/* 4.关闭文件 */
	close(fd);
	return 0;
}

5. dup函数

【1】头文件:#include <unistd.h>

【2】函数原型:int dup(int oldfd);

【3】功能:将生成的文件描述符指向传入的oldfd指向的结构体,而不会新建一个结构体。

【4】返回值:新生成的文件描述符。 

【5】示例:假设本地已有一个1.txt文件,当我们通过下列程序去读1.txt文件时,执行结果为:①fd = 3, fd2 = 4, fd3 = 5 ②fd: 1, fd2: 1, fd3 : 2

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv)
{
	//命令行判定
	if (argc != 2) {
		printf("请输入下列格式:%s <文件名>\n", argv[0]);
		return -1;
	}
	//dup功能检验
	int fd = open(argv[1], O_RDONLY);	//会新建一个结构体
	int fd2 = open(argv[1], O_RDONLY);	//会新建一个结构体
	int fd3 = dup(fd);	//不新建,而是指向fd的结构体
	printf("fd = %d, fd2 = %d, fd3 = %d\n", fd, fd2, fd3);
	//读取同一个文件
	char c1, c2, c3;
	read(fd, &c1, 1);	//fd中的pos往后移动
	read(fd2, &c2, 1);	//fd2中的pos往后移动
	read(fd3, &c3, 1);	//由于fd3指向fd结构体,fd中的pos往后移动
	printf("fd: %c, fd2: %c, fd3 : %c\n", c1, c2, c3);
	//关闭文件
	close(fd);
	close(fd2);
	return 0;
}

6. dup2函数

【1】头文件:#include <unistd.h>

【2】函数原型:int dup2(int oldfd, int newfd);

【3】功能:重定向。以dup2(fd, 1)为例说明:①关闭文件句柄1的文件;②将文件句柄1指向fd对应的file结构体。因此,之后涉及文件句柄1的操作都作用于fd所指的文件。如下图所示:

【4】返回值:newfd。 一般不关注这个返回值。

【5】示例:假设我们有个1.txt文件,执行下列程序后,命令行中并未出现字符串,而字符串"fd = 3, fd = 1"出现在了1.txt文件中。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
	int fd = open(argv[1], O_RDWR);
	int fd2 = dup2(fd, 1);
	printf("fd = %d, fd2 = %d\n", fd, fd2);
	close(fd);
	return 0;
}


二、文件读写细节

1. 换行符

  • Windows中:换行为"\r\n"
  • Linux中:换行为"\n"
  • Mac中:换行为"\r"

2. 文件描述符

  • 文件描述符是一种文件的"ID"。通过文件描述符,我们可以对其指向的文件进行读写操作。
  • 在一个进程中,每次调用open函数打开一个文件,都会生成一个新的文件描述符(不会与已有的重复)。
  • 不同进程的文件描述符是相互独立的。
  • 一个进程中默认会有三个文件描述符:0指向标准输入(键盘),1指向标准输出(命令行),2指向错误信息的输出(命令行)。

3. errno和perror

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

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

相关文章

为什么美业门店要用专业的美业系统?博弈美业SaaS管理系统Java源码分享

美容、医美等美业门店需要使用专业的美业系统&#xff0c;而不是普通的管理系统&#xff0c;美业专用系统的优势在哪&#xff1f; 专业的美业系统与普通系统相比&#xff0c;更加贴合美业门店的经营需求&#xff0c;提供了更全面、便捷、高效的管理功能&#xff0c;有助于提升…

端到端自动驾驶的基础概念

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.端到端自动驾驶的定义 1.1特斯拉FSD 1.2端到端架构演进 1.3大模型 1.4世界模型 1.5纯视觉传感器 2.落地的挑战 1.端到端自动驾驶的定…

RSA学习

[MRCTF2020]Easy_RSA 先来分析一下这个RSA代码的特殊性&#xff0c;这个不是传统的RSA,随机生成N&#xff0c;并保证为N%8的余数是5 zlib 用于数据压缩&#xff0c;但是并似乎没有用到 gen_p(): 生成随机的1024位质数p。计算np*q&#xff0c;并没有直接用于加密。计算F_n…

返回给前端数据的封装

返回格式如下&#xff1a; { "code": 200/400, "msg": "成功"/"失败", "total": n, "data": [ {}&#xff0c;{}]} 1.在common中新增Result 类&#xff0c;代码如下 package com.xxx0523.common; import lombo…

【OpenVINO™】使用 OpenVINO™ C# 异步推理接口部署YOLOv8 ——在Intel IGPU 上速度依旧飞起!!

OpenVINO Runtime支持同步或异步模式下的推理。Async API的主要优点是&#xff0c;当设备忙于推理时&#xff0c;应用程序可以并行执行其他任务&#xff08;例如&#xff0c;填充输入或调度其他请求&#xff09;&#xff0c;而不是等待当前推理首先完成。 当我们使用异步API时&…

【React】使用Token做路由权限控制

在components/AuthRoute/index.js中 import { getToken } from /utils import { Navigate } from react-router-domconst AuthRoute ({ children }) > {const isToken getToken()if (isToken) {return <>{children}</>} else {return <Navigate to"/…

算法设计与分析 实验4 动态规划法求扔鸡蛋问题

目录 一、实验目的 二、问题描述 三、实验要求 四、实验内容 动态规划法 算法描述 算法伪代码描述 算法复杂度分析 数据测试 二分优化的动态规划法 算法描述 二分优化&#xff1a; 算法伪代码 算法复杂度分析 数据测试 单调决策优化的动态规划法 算法描述 算…

【机器学习】与【深度学习】的前沿探索——【GPT-4】的创新应用

gpt4o年费&#xff1a;一年600&#xff0c; 友友们&#xff0c;一起拼单呀&#xff0c;两人就是300&#xff0c;三个人就是200&#xff0c;以此类推&#xff0c; 我已经开通年费gpt4o&#xff0c;开通时长是 从2024年6月20日到2025年7月16日 有没有一起的呀&#xff0c;有需要的…

vue3页面传参

一&#xff0c;用query传参 方法&#xff1a; router.push({path: ‘路由地址’, query: ‘参数’}) 例子&#xff1a;a页面携带参数跳转到b页面并且b页面拿到a页面传递过来的参数 在路由router.ts配置 a页面&#xff1a; <template><div >a页面</div>…

Spatio-temporal Relation Modeling for Few-shot Action Recognition

标题&#xff1a;少样本动作识别的时空关系建模 源文链接&#xff1a;Thatipelli_Spatio-Temporal_Relation_Modeling_for_Few-Shot_Action_Recognition_CVPR_2022_paper.pdf (thecvf.com)https://openaccess.thecvf.com/content/CVPR2022/papers/Thatipelli_Spatio-Temporal_…

多目标跟踪中用到的求解线性分配问题(Linear Assignment Problem,LAP)Python

多目标跟踪中用到的求解线性分配问题&#xff08;Linear Assignment Problem&#xff0c;LAP&#xff09;Python flyfish 如果想看 C版本的&#xff0c;请点这里。 线性分配问题&#xff08;LAP&#xff0c;Linear Assignment Problem&#xff09;是一个经典的优化问题&…

虚拟机配置桥接模式

背景 因为要打一些awd比赛,一些扫描工具什么的,要用到kali,就想着换成一个桥接模式 但是我看网上的一些文章任然没弄好,遇到了一些问题 前置小问题 每次点开虚拟网络编辑器的时候都没有vmnet0,但是点击更改的时候却有vmnet0 第一步: 点击更改设置 第二步: 把wmnet0删掉 …

AD使用快捷键

1、如何实现元器件旋转45放置 在Preferences >> PCB Editor >> General中将Rotation Step&#xff08;旋转的步进值&#xff09;由90改为45&#xff0c;这样以后每次按空格键旋转器件时旋转角度为45。 2、显示网络、隐藏网络 N 3、对齐 2、设置DRC检查选项&#xf…

[17] 使用Opencv_CUDA 进行滤波操作

使用Opencv_CUDA 进行滤波操作 邻域处理操作 > 滤波操作&#xff0c;拒绝或者允许某特定频段通过如果图像某处的灰度级变化缓慢&#xff0c;那么就是低频区域&#xff0c;如果灰度级变化剧烈&#xff0c;就是高频区域邻域滤波即卷积操作形态学处理&#xff1a;膨胀&#xf…

vue小总结

知识总结 【 1 】es6 语法总结 # let 定义变量 # const定义常量 ------块级作用域---- # var 以后尽量少用&#xff0c;函数作用域var 在 JavaScript 中是函数作用域或全局作用域。而 let 和 const 是块级作用域。 // 使用 var 声明全局变量 var globalVar "Im a globa…

酸性设计震撼登场,让你眼前一亮!

说起酸性&#xff08;ACID&#xff09;&#xff0c;你会想到什么&#xff1f;”我们通常会想到酸味&#xff0c;酸设计的视觉魅力是通过图形、颜色、排版给人复古、迷幻、黑暗、叛逆的感觉&#xff0c;反复几何图形和高饱和的颜色&#xff0c;使设计非常时尚&#xff0c;非常适…

linux精通 4.1

2.1.3 http服务器实现 目的 reactor应用——webserver webclient 每次上课前 看大纲down code 复习&#xff1a; 不行啊 编译给的代码报错啊 给的最新的不是0430那一版就不行啊 reactor.c:(.text0x254): relocation truncated to fit: R_X86_64_PC32 against symbol begin de…

Unity 材质系统优化(mesh相同,图片不同,但是可以将所有的图片合成一张图集)

今天提供一个Unity材质优化的思路&#xff0c;流程是这样的&#xff0c;模型的mesh相同只是图片不同&#xff0c;我想着能不能将所有的图片合成一张图集呢&#xff0c;于是我就试着在Blender里面开搞了&#xff0c;所有的mesh相同的模型&#xff0c;共用一个材质&#xff08;图…

分支结构相关

1.if 语句 结构&#xff1a; if 条件语句&#xff1a; 代码块 小练习&#xff1a; 使用random.randint()函数随机生成一个1~100之间的整数&#xff0c;判断是否是偶数 import random n random.randint(1,100) print(n) if n % 2 0:print(str(n) "是偶数") 2.else语…

Unity3d 游戏暂停(timeScale=0)引起的deltaTime关联的系列问题解决

问题描述 游戏暂停的功能是通过设置timeScale0实现的&#xff0c;不过在暂停游戏的时候&#xff0c;需要对角色进行预览和设置&#xff0c;为了实现这个功能&#xff0c;是通过鼠标控制相机的操作&#xff0c;为了使相机的操作丝滑&#xff0c;获取鼠标操作系数乘以Time.delta…