news 2026/8/25 19:35:04

【linux应用软件编程】文件操作学习3【目录IO、出错处理及framebuffer基础操作】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【linux应用软件编程】文件操作学习3【目录IO、出错处理及framebuffer基础操作】

文章目录

  • 前言
  • 一、目录IO
    • 1.1 打开目录文件:opendir()
    • 1.2 读取目录文件:readdir()
    • 1.3 关闭目录文件:closedir()
    • 1.4 文件夹创建:mkdir()
    • 1.5 使用示例:目录遍历
  • 二、出错处理
    • 2.1 strerror
    • 2.2 perror
  • 三、framebuffer
    • 3.1 什么是framebuffer:
    • 3.2 如何操作framebuffer
      • 3.2.1 打开显示设备文件
      • 3.2.2 获取显示设备的相关参数
      • 3.2.3 建立内存映射
      • 3.2.4 写入RGB颜色值;
      • 3.2.5 解除内存映射与关闭显示设备文件

前言

上篇文章我们学习了文件相关基础知识及标准IO和文件IO,这篇文章,我们主要是对文件IO的一个补充即目录IO的学习,还有对出错处理的一个学习,以及对之前C语言五子棋项目实战中framebuffer帧缓存技术的补充学习。下面是之前相关知识的博客文章,感兴趣的可以看一看:
文件相关基础知识及【标准IO】
文件IO及文件IO与标准IO的区别
基于【C语言】和【framebuffer】的五子棋游戏项目

一、目录IO

  1. 打开目录文件:opendir()
  2. 读取目录文件:readdir()
  3. 关闭目录文件:closedir()

1.1 打开目录文件:opendir()

  • 函数原型:
    #include<sys/types.h>#include<dirent.h>DIR*opendir(constchar*name);
  • 功能:

    打开目录文件并获得目录流指针。

  • 参数:

    name:目录文件名。

  • 返回值:

    成功:返回目录流指针;
    失败:返回NULL。

1.2 读取目录文件:readdir()

  • 函数原型:
    #include<dirent.h>structdirent*readdir(DIR*dirp);
  • 功能:

    从目录流中读取数据。

  • 参数:

    dirp:目录流指针。

  • 返回值:

    成功:;
    文件末尾:NULL;
    失败:NULL。

1.3 关闭目录文件:closedir()

  • 函数原型:
    #include<sys/types.h>#include<dirent.h>intclosedir(DIR*dirp);
  • 功能:

    关闭目录文件。

  • 参数:

    dirp:目录流指针。

  • 返回值:

    成功:返回0;
    失败:返回-1.

1.4 文件夹创建:mkdir()

  • 函数原型:
#include<sys/stat.h>#include<sys/types.h>intmkdir(constchar*pathname,mode_tmode);
  • 功能:

    创建一个文件夹。

  • 参数:

    pathname:创建的文件夹的名称;
    mode:权限设置。

  • 返回值:

    成功:返回0;
    失败:返回-1。

1.5 使用示例:目录遍历

通过调用opendir打开上级目录,通过readdir循环读取目录项信息,打印每个文件的文件名、inode 编号,依据dirent结构体中的d_type字段识别并输出文件类型,最后调用closedir关闭目录,完成目录遍历。

#include<stdio.h>#include<dirent.h>voidget_type(structdirent*pinfo){switch(pinfo->d_type){caseDT_BLK:printf("%s : b\n",pinfo->d_name);break;caseDT_CHR:printf("%s : c\n",pinfo->d_name);break;caseDT_DIR:printf("%s : d\n",pinfo->d_name);break;caseDT_FIFO:printf("%s : p\n",pinfo->d_name);break;caseDT_LNK:printf("%s : l\n",pinfo->d_name);break;caseDT_REG:printf("%s : -\n",pinfo->d_name);break;caseDT_SOCK:printf("%s : s\n",pinfo->d_name);break;default:printf("%s : unknow\n",pinfo->d_name);break;}}intmain(){DIR*pdir=opendir("..");if(NULL==pdir){printf("opendir error!\n");return-1;}while(1){structdirent*pinfo=readdir(pdir);if(NULL==pinfo){break;}printf("%s : %ld\n",pinfo->d_name,pinfo->d_ino);get_type(pinfo);}closedir(pdir);return0;}

二、出错处理

2.1 strerror

  • 函数原型:
    #include<string.h>char*strerror(interrnum);
  • 功能:

    将错误码转化为对应的错误信息字符串。

  • 参数:

    errnum:错误码(errno)。

  • 返回值:

    成功:返回对应错误信息字符串的首地址;
    失败:返回NULL。

  • 注意:

    使用errno需要包含errno.h这个头文件。

2.2 perror

  • 函数原型:

    #include<stdio.h>voidperror(constchar*s);
  • 功能:

    打印自己的出错信息和系统给出的出错原因。

  • 参数:

    自己的出错信息字符串。

  • 返回值:

    无返回值。

三、framebuffer

3.1 什么是framebuffer:

  1. 帧缓存、帧缓冲技术;
  2. 是Linux为显示设备提供的一个接口,把显存抽象后的一种设备文件,通过该设备文件可以实现应用层向显存空间的数据写入,从而实现像素点的绘制。

3.2 如何操作framebuffer

通过内存映射技术,可以实现显存空间和用户空间的内存映射,通过向用户空间写入RGB颜色值,从而实现显存数据的写入。

像素点位数/位深度的种类:

  • RGB888 四个字节
  • RGB565 两个字节

framebuffer的操作流程:

  1. 打开显示设备文件/dev/fb0;
  2. 获取显示设备的相关参数(分辨率、像素点位数/位深度);
  3. 建立内存映射;
  4. 写入RGB颜色值;
  5. 解除内存映射;
  6. 关闭显示设备文件。

3.2.1 打开显示设备文件

通过我们的文件IO的函数接口open()打开framebuffer的设备文件,它在/dev/fb0这个目录下,

//1. 打开fb=open("/dev/fb0",O_RDWR);if(-1==fb){perror("open /dev/fb0 error");return-1;}

3.2.2 获取显示设备的相关参数

我们通过ioctl()这个系统调用的函数接口来获取设备的相关参数;

它的描述是这样的:
ioctl()系统调用用于操控特殊文件底层对应的设备参数。参数fd必须是一个已经成功打开的文件描述符。第二个参数是依赖具体设备的请求命令码(request)。不同驱动,命令码含义完全不一样,没有全局统一标准。第三个参数是一个无类型的内存指针。历史上C 语言还没有void*时,这里约定使用char *argp,所以手册后续讲解中将它命名为argp。也就是原型里的可变参数,你可以传任意类型指针。

linux@ubuntu:/usr/include/linux$这个路径下的的fb.h文件是Linux 液晶屏帧缓冲驱动专用头文件,里面定义了 Framebuffer 设备 (/dev/fb0) 所有可用的ioctl命令码。

例如:

  1. FBIOGET_VSCREENINFO:这个宏就是我们现在需要的获取虚拟屏幕可变信息的命令码(分辨率、色深、像素格式等)。
  2. 还有这个:struct fb_var_screeninfo 可变屏幕信息结构体:
    structfb_var_screeninfo{__u32 xres;/* visible resolution */__u32 yres;__u32 xres_virtual;/* virtual resolution */__u32 yres_virtual;__u32 xoffset;/* offset from virtual to visible */__u32 yoffset;/* resolution */__u32 bits_per_pixel;/* guess what */__u32 grayscale;/* 0 = color, 1 = grayscale, *//* >1 = FOURCC */structfb_bitfieldred;/* bitfield in fb mem if true color, */structfb_bitfieldgreen;/* else only length is significant */structfb_bitfieldblue;structfb_bitfieldtransp;/* transparency */__u32 nonstd;/* != 0 Non standard pixel format */__u32 activate;/* see FB_ACTIVATE_* */__u32 height;/* height of picture in mm */__u32 width;/* width of picture in mm */__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */};
    成员变量含义说明
    xres/yres可见屏幕分辨率(实际 LCD 显示宽高像素)
    例:800×480,xres=800,yres=480
    xres_virtual/yres_virtual虚拟显存分辨率
    显存可以开辟一块比屏幕更大的画布,用于硬件滚屏、双缓冲。
    例如虚拟高度设为yres*2实现页面翻页
    xoffset/yoffset显示偏移量:从虚拟显存的(xoffset,yoffset)位置开始截取画面输出到屏幕
    修改yoffset配合大的yres_virtual,即可实现硬件滚动 (Panning)
    bits_per_pixel每个像素占用比特数,色深
    常见值:16 (RGB565)、24 (RGB888)、32 (RGBA8888)
    grayscale灰度模式标志
    0= 彩色;1= 灰度;大于 1 代表使用 FOURCC 压缩图像格式
    red/green/blue/transpRGB 分量位域信息,struct fb_bitfield结构体
    包含每个颜色通道:起始偏移位、占用位数。
    👉RGB565:红占 5bit,绿占 6bit,蓝占 5bit
    nonstd非标准像素格式标记,非 0 代表不是标准 RGB 格式
    activate参数生效时机。控制调用FBIOPUT_VSCREENINFO后,新分辨率是立刻生效还是等到下一次 vsync 垂直同步
    height/width屏幕物理尺寸,单位:毫米 (mm),用于计算 DPI,不影响像素绘图
    accel_flags硬件加速标志,已经废弃,不再使用

代码示例:

//2. 获取显示设备的相关参数structfb_var_screeninfovinfo;intret=ioctl(fb,FBIOGET_VSCREENINFO,&vinfo);if(-1==ret){perror("ioctl error");return-1;}printf("vinfo.xres = %d, vinfo.yres = %d\n",vinfo.xres,vinfo.yres);printf("vinfo.xres_virtual = %d, vinfo.yres_virtual = %d\n",vinfo.xres_virtual,vinfo.yres_virtual);printf("vinfo.bits_per_pixel = %d\n",vinfo.bits_per_pixel);

3.2.3 建立内存映射


以这两张图为例:Linux帧缓冲通过mmap将位于内核空间的物理显存映射到用户进程虚拟地址空间,程序获得映射指针pmem后,便可利用公式*(pmem + y*w + x)直接计算像素偏移,通过指针赋值直接修改显存数据,无需调用read/write,显存更新后硬件自动刷新到800×600的显示屏上,实现屏幕绘图。显存可开辟一块大于实际屏幕xres × yres的虚拟画布xres_virtual × yres_virtual,屏幕仅截取画布的一部分画面进行显示,修改x_offsety_offset显示偏移量,无需移动显存像素数据,就能快速切换可视区域,从而实现硬件滚屏、双缓冲翻页效果。

  • mmap()
    • 函数原型:
      #include<sys/mman.h>void*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);
    • 功能

      建立文件和用户空间的内存映射。

    • 参数

      addr:要映射的用户空间的首地址,一般情况下填NULL,让内核自己寻找一块连续的内存空间,并将空间首地址返回;
      length:要映射的用户空间大小;
      prot:对映射空间的读写权限
      1. PROT_READ
      2. PROT_WRITE
      flags:MAP_SHARED(共享映射区域)
      fd:要映射的文件描述符;
      offset:映射的偏移量

    • 返回值

      成功:返回映射到的用户空间首地址;
      失败:返回MAP_FAILED((void *)-1)。

内存映射代码示例:

void*pmem=NULL;//3. 建立内存映射len=vinfo.xres_virtual*vinfo.yres_virtual*vinfo.bits_per_pixel/8;pmem=mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);if(MAP_FAILED==pmem){perror("mmap error");return-1;}

3.2.4 写入RGB颜色值;

首先校验像素坐标是否超出可视屏幕范围,随后基于虚拟显存宽度计算目标像素的内存偏移,通过显存映射指针pmem直接向帧缓冲写入指定颜色值,完成单点绘制。

voidshow_point(intx,inty,unsignedintcol){//4. 写入RGB颜色值if(x>=vinfo.xres||y>=vinfo.yres){return;}*((unsignedint*)pmem+y*vinfo.xres_virtual+x)=col;}

3.2.5 解除内存映射与关闭显示设备文件

  • munmap()
    • 函数原型:

      #include<sys/mman.h>intmunmap(void*addr,size_tlength);
    • 功能:

      解除mmap()建立的内存映射,释放用户空间与物理显存之间的映射关系;取消后不能再通过该指针访问显存,关闭帧缓冲文件前必须调用。

    • 参数:

      1. addrmmap返回的映射起始虚拟地址(如前面的pmem
      2. length:需要解除映射的内存字节长度,显存映射大小(finfo.smem_len
    • 返回值:

      成功:返回0
      失败:返回-1,并设置errno错误号

代码示例:

voiddeinit_fb(){//5. 解除内存映射;munmap(pmem,len);//6. 关闭显示设备文件。close(fb);}

通过这些步骤我们就可以绘制一个点了,再借助这个点绘制的函数接口,我们就可以进一步封装其他绘制函数了,等下一篇文章我将进一步分享通过framebuffer绘制bmp格式图片的方法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/25 19:34:49

当 AI 会写代码之后,软件还剩什么?

导语&#xff1a;从一句"AI 编程直接生成 C/汇编你怎么看"出发&#xff0c;我推演了一个完整闭环&#xff0c;又亲手把它推翻了一半。这篇是复盘&#xff0c;也是一份诚实的研究记录。前几天刷到一篇内容是说&#xff1a;AI 编程直接生成 C 语言或者汇编语言&#xf…

作者头像 李华
网站建设 2026/8/25 19:32:47

2026年事业单位面试拉开帷幕,哪家机构师资强值得一探究竟!

2026 年事业单位面试的大幕已经徐徐拉开&#xff0c;众多考生在备考之路上都在苦苦寻觅一家师资力量强大的培训机构来助力自己成功上岸。毕竟&#xff0c;专业且经验丰富的师资是备考过程中至关重要的一环&#xff0c;他们能够为考生提供精准的指导、实用的技巧和宝贵的经验分享…

作者头像 李华
网站建设 2026/8/25 19:31:42

人形机器人技术进阶:从概念验证到综合工程能力实战

上周&#xff0c;我偶然点开一个科技新闻&#xff0c;标题是“第二届世界人形机器人运动会今天开幕&#xff0c;新增拔河、乒乓球等项目”。说实话&#xff0c;第一反应是觉得有点“萌”&#xff0c;脑海里浮现出几个金属骨架在赛场上笨拙移动的画面&#xff0c;这更像是一场科…

作者头像 李华
网站建设 2026/8/25 19:29:41

热线知识库搭建方法论:结构化存储、智能检索、动态更新机制

在政务便民热线、企业客服热线、售后咨询热线等服务场景中&#xff0c;知识库是一线坐席应答、智能机器人回复、服务标准化落地的核心底座。很多热线团队常会遇到这类问题&#xff1a;知识内容杂乱无章、新旧信息混杂、相似问题答案不统一、坐席检索耗时久、新规政策无法及时同…

作者头像 李华
网站建设 2026/8/25 19:29:33

室内智能晾衣架系统

智云创客平台是一个集开源节点、无线模组和感知设备于一体的创新产品&#xff0c;特别适用各类竞赛、学生毕业设计以及企业实训课&#xff0c;助力用户实现无限创意&#xff0c;探索无限可能。今天给大家介绍的室内智能晾衣架系统是系列之一。关键技术室内智能晾衣架系统主要涉…

作者头像 李华
网站建设 2026/8/25 19:23:55

2026软件测试面试八股文与实战技巧全解析

1. 2026软件测试面试八股文全景解析在软件测试行业摸爬滚打多年&#xff0c;我深刻体会到面试准备的重要性。2026年的测试岗位竞争愈发激烈&#xff0c;掌握系统化的面试知识体系已成为求职者的必修课。这份八股文资料不同于网上零散的面试题集合&#xff0c;而是按照测试工程师…

作者头像 李华