嵌入式应用开发|Linux文件I/O常用的四种访问方式

news2024/12/28 3:13:14

    在Linux系统中,一切都可以看成"文件"<通常包含:普通文件、驱动文件、网络通信文件等等>,系统中所有的操作都可以通过文件I/O实现,因此,掌握文件常用接口很有必要。

0.前言

     屏幕前的你如果懂得main函数传递参数机制,可以跳过本部分直接看后续内容。

    在正式内容开始前,小编想讲述Linux中main函数传参的机制。

  • linux中main函数抢先看:
int main(int argc , char* argv[])
  • 函数参数说明:

      • int arc:整型,表示传入参数的个数;
      • char* argv[]:字符型数组,表示实际传入的参数,该参数还存在另一种定义方式,即char argv[][];
  • 实际使用样例:

    • 样例函数
#include <stdio.h>

int main(int argc,char*argv[])
{
 	//打印参数个数
 	printf("argc:%d\n",argc);
 	//遍历参数并且打印
 	printf("argv:");
 	for(int i=0;i<argc;i++)
 	{
 		printf("%s ",argv[i]);
 	}
 	printf("\n");
 	return 0;
}
  • 运行结果
    图片alt
    • 这里需要注意的是运行命令*./test也是传入main函数的参数**。

1.Linux系统中文件来源

  • 来源于磁盘、flash、SD卡等,这些文件是真实存在的,通常以某种格式存储在某个设备上;
  • 内核产生的虚拟文件系统,这些文件并不是真实存在的,但是支持真实文件的操作;
  • 特殊文件,特殊文件可以是字符设备文件、块设备文件等;

2.访问方式

    文件访问函数通常可分为:通用的I/O函数与非通用的I/O访问函数;

  • 通用访问I/O的函数
    • open:打开文件;
    • read:读取文件;
    • write:写入文件;
    • lseek:定位文件内容;
    • close:关闭文件;
  • 非通用访问文件I/O的函数:
    • ioctl:设备控制接口函数
    • mmap:文件映射函数;

查询方式访问

    查询方式,设备文件以非阻塞方式打开后,不断发送读取文件请求的一种方式。例如:当你找人有急事时,就会一直尝试联系某人,这就类似于文件的查询方式。

    由于查询方式是不断发送读取请求,因此它访问次数非常频繁占用CPU资源相对较多

核心代码

#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>

int main(int argc, char const *argv[])
{
  int fd = 0;
  int err = 0;
  struct input_id id;
  unsigned int evbit[2];
  int len,res;
  struct input_event event;
  
  //判断参数个数是不是2 一个运行参数  一个文件设备
  if (argc != 2)
	{
		printf("Usage: %s <dev>\n", argv[0]);
		return -1;
	}
	/* 打开驱动程序 */
	fd = open(argv[1], O_RDWR | O_NONBLOCK);
	//打开失败 返回
    if (fd < 0)
	{
		printf("open %s err\n", argv[1]);
		return -1;
	}
  //不断查询方式 非阻塞
  while(1)
  {
  	//读取数据并判断数据大小是否正确
    len = read(fd,&event,sizeof(event));
    if(len == sizeof(event))
    {
      printf("get event:type=0x%x code=0x%x value=0x%x\n",event.type,event.code,event.value);
    }
    else
    {
      printf("read err\n");
    }
  }
}

休眠唤醒方式访问

    休眠唤醒方式,这里是指:首先文件以阻塞方式打开,当读取到文件数据时,阻塞态就会转换为运行态,读取出数据会直接返回,进行下一步操作。比如:大家在学校上课时(这里将上课作为阻塞态,下课作为运行态),一旦上课铃声响起,咱就会进入阻塞态上课;而下课铃声想起后,大家就开始运行了,进入运行态,直接起飞。🤓🤓🤓

    休眠唤醒方式,占用CPU资源相对较少请求次数相对减少;但是,一旦没有请求到数据就会一直进入阻塞,不会干其他活,这就大大限制了进程的运行状态。

核心代码

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


int main(int argc, char **argv)
{
	int fd;
	int err;
	int len;
	int i;
	unsigned char byte;
	int bit;
	unsigned int evbit[2];
	struct input_event event;
	//判断参数个数是不是2 一个运行参数  一个文件设备
	if (argc != 2)
	{
		printf("Usage: %s <dev> err\n", argv[0]);
		return -1;
	}
	/* 打开驱动程序 */
	fd = open(argv[1], O_RDWR);
	//打开失败 返回
	if (fd < 0)
	{
		printf("open %s err\n", argv[1]);
		return -1;
	}
	//不断查询 阻塞
	while (1)
	{
		//读取数据 并且判断数据大小是否正确
		len = read(fd, &event, sizeof(event));
		if (len == sizeof(event))
		{
			printf("get event: type = 0x%x, code = 0x%x, value = 0x%x\n", event.type, event.code, event.value);
		}
		else
		{
			printf("read err %d\n", len);
		}
	}
	return 0;
}


以POLL/SELECT方式访问

    POLL/SELECT方式访问,首先文件以非阻塞方式打开,再使用poll()函数设置一个固定的超时时间。在这段超时时间内,如果文件能够读出或写入时就会立即返回;否则,时间超时后返回错误

  • 函数原型
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • 参数说明

    • struct pollfd {
          int   fd;         /* file descriptor,目标文件*/
          short events;     /* requested events,操作事件*/
          short revents;    /* returned events,超时事件返回值*/
      };
      
    • nfds_t nfds;          /*事件的个数*/
      
    • int timeout;		  /*设置超时时间*/
      

核心代码

#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>

int main(int argc, char const *argv[])
{
  int fd = 0;
  int err = 0;
  unsigned int evbit[2];
  int len,res;
  struct input_event event2;
  struct pollfd fds[1];
  nfds_t nfds = 1;
    
  //poll-seelct  设置一个固定的时间查询输入事件
  if(argc!=2)
  {
    printf("err\n");
    return 0-1;
  }
  //以非阻塞的方式打开
  fd = open(argv[1],O_RDWR|O_NONBLOCK);
  if(fd < 0 )
  {
      printf("open %s err\n",argv[1]);
      return -1;
  }

  while(1)
  {
  //设置监听事件相关参数
    fds[0].fd = fd;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    res = poll(fds,nfds,5000);
      
    //返回值有效
    if(res > 0)
    {
      //判断事件方式是否数输入方式
      if(fds[0].revents == POLLIN)
      {
        //数据读取完成后返回
        while(read(fd,&event,sizeof(event))==sizeof(event))
        {
          printf("get event:type=0x%x code=0x%x value=0x%x\n",event.type,event.code,event.value);
        }
      }
    }
    else if(res == 0)
    {
      printf("time out\n");
    }
    else
    {
      printf("poll err\n");
    }

  }
  return 0;
}

异步通知方式

    异步通知方式,文件是以非阻塞方式打开的,在初始化设置完成后,当没有读取到数据时,程序可以干其他的事,读取数据操作并不影响程序的其他操作。看到这儿,大家是不是觉得这种处理方式很类似于单片机的中断处理函数。😸😸😸

    异步通知方式,使用了信号量,信号量在此处的作用是通知驱动程序是否能够成功读取数据,能够成功读取数据后,驱动就读取数据;否则就将其闲置在一旁。

代码

#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>

int fd = 0;
struct input_event event;

void my_sig_handler(int sing)
{
  while(read(fd,&event,sizeof(event))==sizeof(event))
  {
    printf("get event:type=0x%x code=0x%x value=0x%x\n",
    			event.type,event.code,event.value);
  }
}

int main(int argc, char const *argv[])
{
  int fd2 = 0;
  int err = 0;
  struct input_id id;
  unsigned int evbit[2];
  int len,res;
  struct input_event event2;

  struct pollfd fds[2];
  nfds_t nfds = 2;
  unsigned int count = 0,flags;
  //判断参数个数是不是2 一个运行参数  一个文件设备
  if (argc != 2)
  {
		printf("Usage: %s <dev>\n", argv[0]);
		return -1;
  }

  /* 注册信号处理函数 */
  signal(SIGIO, my_sig_handler);
  /* 打开驱动程序 */
  fd = open(argv[1], O_RDWR | O_NONBLOCK);
  if (fd < 0)
  {
        printf("open %s err\n", argv[1]);
        return -1;
  }

  /* 把APP的进程号告诉驱动程序 */
  fcntl(fd, F_SETOWN, getpid());
  /* 使能"异步通知" */
  flags = fcntl(fd, F_GETFL);
  fcntl(fd, F_SETFL, flags | FASYNC);
    
  while(1)
  {
  	//主进程干的活
    printf("count:%d\n",count++);
    sleep(2);
  }
  return 0;
}

3.小结

    尽管,上文的四种文件访问方式各有优劣,但只要在合适的时机使用就能够发挥其最大效率!

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

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

相关文章

SAP S4 如何快速配置一家公司

之前配置公司采用的方法是copy的方式来配置&#xff0c;后来在做其他配置的时候发现&#xff0c;copy的方法会把很多不需要的配置也copy进来了。所就我从新定义了一个公司来进行学习研究。配置一定空的公司很简单&#xff0c;只需要三步&#xff1a; 1 定义和分配公司 • 公司…

Java中的异常、IO与NIO面试题

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java面试题…

萤石网络通过注册:9个月净利2亿同比降28% 海康威视为大股东

雷递网 雷建平 12月19日杭州萤石网络股份有限公司&#xff08;简称&#xff1a;“萤石网络”&#xff09;日前通过注册&#xff0c;准备在科创板上市。萤石网络计划募资37.39亿元&#xff0c;其中&#xff0c;22亿元用于萤石智能制造重庆基地项目&#xff0c;8亿元用于新一代物…

论文投稿指南——中文核心期刊推荐(航空、航天)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

做Python网络爬虫需要掌握哪些核心技术?

在当下这个社会&#xff0c;如何有效地提取并利用信息成为一个巨大的挑战。基于这种巨大的市场需求&#xff0c;爬虫技术应运而生&#xff0c;这也是为什么现在爬虫工程师的岗位需求量日益剧增的原因。那么做Python网络爬虫需要掌握哪些核心技术呢&#xff1f;下面我们来一起看…

机器学习 特征工程及模型聚合

目录 一&#xff1a;什么是特征工程 二&#xff1a;特征工程方法 三&#xff1a;独热编码 四&#xff1a;归一化处理 五&#xff1a;特征工程方法 六&#xff1a;特征工程处理过程 七&#xff1a;Kaggle房价预测实际案例 一&#xff1a;什么是特征工程 1 是最大限度地从…

React源码分析6-hooks源码

本文将讲解 hooks 的执行过程以及常用的 hooks 的源码。 hooks 相关数据结构 要理解 hooks 的执行过程&#xff0c;首先想要大家对 hooks 相关的数据结构有所了解&#xff0c;便于后面大家顺畅地阅读代码。 Hook 每一个 hooks 方法都会生成一个类型为 Hook 的对象&#xff…

学习->C++篇十八:一文总结C++的异常

目录 C为什么要引入异常&#xff1f; 什么是异常&#xff1f; 怎么使用异常处理错误&#xff1f; 异常的抛出规则&#xff1a; 异常的匹配规则&#xff1a; 单个catch语句&#xff0c;不能完全处理掉异常&#xff1f;重新抛出异常 什么是异常安全问题&#xff1f; 什么…

一、绘制折线图

Origin-绘图 一、新建绘图表格 Add New Column&#xff1a;新建一列 Set as→Y Error设置新列为Y误差 Long Name&#xff1a;X轴和Y轴名称&#xff1b;Units&#xff1a;单位&#xff1b;Comments&#xff1a;注释&#xff1b; 二、绘图 绘制折线图&#xff1a; 选择X、Y、…

2022年,转行IT学哪些编程语言更容易拿高薪?

人们都说年头年尾都是给自己进行规划最好的时段&#xff0c;想要学习编程的你现在是不是也开始进行规划了呢&#xff1f; 不过对大部分人来说&#xff0c;最犹豫的问题也摆在面前&#xff0c;编程语言众多&#xff0c;不知道学什么才能对后续的就业和职业发展有更好的作用。 …

PyTorch 2.0 之 Dynamo: 窥探加速背后的真相

前言 PyTorch 2.0 算是正式官宣了&#xff0c;预计在明年 3 月和大家见面。官方的 blog 宣发了非常多的内容&#xff0c;但是阅读下来不难发现&#xff0c;几乎所有的性能提升、体验优化都源自于 PyTorch 新设计的即时编译工具&#xff1a;Dynamo。 PyTorch eager 模式极佳的…

Flink 在米哈游的应用实践

摘要&#xff1a;本文整理自米哈游大数据实时计算团队负责人张剑&#xff0c;在 Flink Forward Asia 2022 主会场的分享&#xff0c;本篇内容主要分为三个部分&#xff1a;发展历程和平台建设场景应用实践未来展望Tips&#xff1a;点击「阅读原文」获取演讲 ppt01发展历程和平台…

分享一种通信协议的应用编程原理和思路

已剪辑自: https://mp.weixin.qq.com/s/wy-flva6pCNqHV3ObeLPCQ 嵌入式开发过程中&#xff0c;UART、 CAN、 USB等通信基本离不开通信协议。 下面给大家分享一种通信协议&#xff08;MAVLink&#xff09;在应用编程中的编程原理和思路。 本节提供“MAVLink发送接收例程”例程下…

[FTP] ftp通信协议抓包分析

想在ESP32上用TCP来实现ftp服务器&#xff0c;抓一下ftp通信包分析一下。总的来说就是两个TCP通道&#xff0c;一个命令通道&#xff0c;一个数据通道&#xff1b;数据通道只有在遍历目录、下载、上传的时候才开启&#xff0c;其余时候均不开启&#xff1b;主要就是协议对接好就…

【认识】wireshark使用教程

本文章&#xff0c;是简单粗暴学习Wireshark的抓包功能后&#xff0c;记录的一些笔记。 1 Wireshark简介及抓包原理及过程 1.1 简介 Wireshark是1个网络封包分析软件。网络封包分析软件的功能是截取网络封包&#xff0c;并尽可能显示出最为详细的网络封包资料。Wireshark使用…

从盒马生鲜迫切转型升级有感而发,疫情之后,路在何方

据悉&#xff0c;针对浦东地区目前突增的需求&#xff0c;市民线上采买生活物资的订单激增&#xff0c;饿了么联合包括每日优鲜、大润发在内的主要生鲜买菜商户&#xff0c;一起增加运力配合&#xff1b;盒马生鲜也对接了上海之外的山东、云南等省外基地&#xff0c;以避免中间…

JVM核心知识详解

文章目录1. JVM内存分配程序计数器虚拟机栈栈帧都有哪些内容栈内存溢出线程运行诊断演示1&#xff08;cpu占用过多&#xff09;演示2&#xff08;死锁&#xff09;本地方法栈堆堆内存诊断jmp诊断堆内存jconsole诊断堆内存jvisualvm诊断堆内存方法区直接内存java操作磁盘文件NIO…

IT行业分析报告:2022年哪个编程语言最受雇主公司喜欢?

2022年哪个编程语言最受雇主公司喜欢&#xff1f; 被认为是朝阳行业的IT互联网&#xff0c;软件工程师的平均年薪只涨了0.8%&#xff0c;再加上这两年互联网“寒冬”的说法&#xff0c;很多人不禁会问&#xff0c;现在还能入行IT互联网吗&#xff1f; 今天给大家整理了一份IT行…

Vue全局共享数据之globalData,vuex,本地存储使用方法

目录 一、globalData 二、vuex存储方式 1.vue2用法&#xff0c;2.vue3用法 三、本地存储 uniapp的数据缓存 写在最前面&#xff0c;把vue能用到的存储方法都整理拿出来&#xff0c;方便阅读以及工作用。&#x1f349;&#x1f349;&#x1f349;可以收藏起来即拿即用 Vue全局共…

杨旸:从边缘智能迈向泛在智能

内容来源&#xff1a;2022年11月12日&#xff0c;在全球边缘计算大会上海站上&#xff0c;我们非常荣幸邀请到了特斯联集团首席科学家杨旸博士来分享&#xff0c;杨旸博士曾任上海科技大学教授、科道书院院长、上海雾计算实验室主任&#xff1b;科技部“第五代移动通信系统&…