2019年7月29日星期一(文件IO)

. 系统IO与标准IO结合实例  -> 显示RGB组成BMP格式图片

1. BMP格式图片特点

由纯RGB三原色来组成,没有经过任何的压缩,文件相对于压缩过jpeg格式会比较大。

test.bmp  -> 1MB

test.jpg  -> 27KB

2. BMP图片既然是RGB组成,那么BMP图片像素点是如何组成?

一般BMP图片都是24位的,因为RGB各占8位,24位说明每一个像素点都是由3个字节字节,从高到低依次是: BGR

液晶LCD像素点,从高到低依次是: ARGB

图片总字节: 800*480*3

LCD总字节:800*480*4

. 分析显示过程

1. test.bmp是普通文件,/dev/fb0是设备文件,所以访问对应文件需要使用不同的IO

2. 大致过程如下:

1)使用标准IO访问test.bmp

2)读取test.bmp的数据  -> 将每一个像素点都应该读取出来

3)使用系统IO访问液晶LCD

4)将图片像素点数据写入到液晶LCD中。  -> 注意像素点的分布。

5)关闭文件和设备即可。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       char bmp_buf[800*480*3];//BMP格式图片缓冲区

       char lcd_buf[800*480*4];//LCD液晶缓冲区

       int ret,lcd;

       int i,j;

       //1. 访问BMP图片

       FILE *fp = fopen("test.bmp","r");

       if(fp == NULL)

              printf("fopen error! ");

       //2. 读取BMP图片的数据

       ret = fread(bmp_buf,sizeof(bmp_buf),1,fp);

       if(ret != 1)

              printf("fread error! ");

       //3. 访问LCD液晶

       lcd = open("/dev/fb0",O_WRONLY);

       if(lcd < 0)

              printf("open error! ");

       for(i=0,j=0;i<800*480*4;i+=4,j+=3)

       {

              lcd_buf[i] = 0;

              lcd_buf[i+1] = bmp_buf[j+2];

              lcd_buf[i+2] = bmp_buf[j+1];

              lcd_buf[i+3] = bmp_buf[j];

       }

      

       //4. 将图片数据写入到LCD液晶屏幕上

       ret = write(lcd,lcd_buf,sizeof(lcd_buf));

       if(ret != sizeof(lcd_buf))

              printf("write error! ");

       //5. 关闭设备与文件

       close(lcd);

       fclose(fp);

       return 0;

}

结果:

形状有了,颜色不对!

 lcd_buf[0]  -> 蓝色

 lcd_buf[1]  -> 绿色

 lcd_buf[2]  -> 红色

 lcd_buf[3]  -> 透明度

修改为:

for(i=0,j=0;i<800*480*4;i+=4,j+=3)

{

       lcd_buf[i] = bmp_buf[j];

       lcd_buf[i+1] = bmp_buf[j+1];

       lcd_buf[i+2] = bmp_buf[j+2];

       lcd_buf[i+3] = 0;

}

3. 发现在LCD在开头有一些数据不是像素点来的,也被读取出来了

   800*480*3=1152000  -> 实际像素点的字节数

   图片实际字节数: 1152054   -> 54个头数据!

4. 上下翻装

   根据逻辑关系退出通项公式

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       char bmp_buf[800*480*3];//BMP格式图片缓冲区

       char lcd_buf[800*480*4];//LCD液晶缓冲区

       char show_buf[800*480*4];

       int ret,lcd;

       int i,j,x,y;

       //1. 访问BMP图片

       FILE *fp = fopen("test.bmp","r");

       if(fp == NULL)

              printf("fopen error! ");

       //2. 跳过BMP图片的54个头数据

       ret = fseek(fp,54,SEEK_SET);

       if(ret != 0)

              printf("fseek error! ");

       //3. 读取BMP图片的数据

       ret = fread(bmp_buf,sizeof(bmp_buf),1,fp);

       if(ret != 1)

              printf("fread error! ");

       //4. 访问LCD液晶

       lcd = open("/dev/fb0",O_WRONLY);

       if(lcd < 0)

              printf("open error! ");

       //5. 像素点赋值

       for(i=0,j=0;i<800*480*4;i+=4,j+=3)

       {

              lcd_buf[i] = bmp_buf[j];

              lcd_buf[i+1] = bmp_buf[j+1];

              lcd_buf[i+2] = bmp_buf[j+2];

              lcd_buf[i+3] = 0;

       }

       //6. 上下翻转

       for(y=0;y<480;y++)

       {

              for(x=0;x<800*4;x++)

              {

                     show_buf[(479-y)*800*4+x] = lcd_buf[y*800*4+x];

              }

       }

       //7. 将图片数据写入到LCD液晶屏幕上

       ret = write(lcd,show_buf,sizeof(show_buf));

       if(ret != sizeof(show_buf))

              printf("write error! ");

       //8. 关闭设备与文件

       close(lcd);

       fclose(fp);

       return 0;

}

. 目录IO

1. 如何访问(打开)目录?   -> opendir()  -> man 3 opendir

windows不一样,linux下访问目录就仅仅是打开目录而已,与路径切换无关。

     #include <sys/types.h>

     #include <dirent.h>

   DIR *opendir(const char *name);

       name: 需要打开的目录的路径

   返回值:

       成功: 目录流指针    -> 打开目录后,默认指向目录中最开头的一项!

       失败: NULL

  验证: 访问目录时,并没有切换到目录下。

#include <sys/types.h>

#include <dirent.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

       system("pwd");

       DIR *dp = opendir("./dir");

       if(dp == NULL)

              printf("opendir error! ");

       system("pwd");

       return 0;

}

2. 关闭目录?  ->  closedir()  -> man 3 closedir

  #include <sys/types.h>

  #include <dirent.h>

 int closedir(DIR *dirp);

   dirp: 目录流指针

 返回值:

       成功:0

       失败:-1

3. 如何切换到目录下?  ->  chdir()  -> man 2 chdir

   #include <unistd.h>

  int chdir(const char *path);

  path: 需要切换的目录路径

   返回值:

       成功:0

       失败:-1

注意:

chdir()参数不是填目录流指针,而是填目录路径。

4. 如何读取目录?  ->  readdir()  -> man 3 readdir

    #include <dirent.h>

   struct dirent *readdir(DIR *dirp);

       dirp: 目录流指针

     返回值:

       成功:结构体指针   struct dirent *

       失败:NULL   -> 当目录读取完了,就会返回NULL。

struct dirent {

               ino_t          d_ino;       //索引号

               off_t          d_off;       //偏移量

               unsigned short d_reclen;    //该目录项的名字长度  

               unsigned char  d_type;      //文件的类型

               char           d_name[256]; //文件的名字

};

d_reclen:

公式: 12+X

       .    -> 1   ->  4   ->  12+4=16

       ..    -> 2   ->  4   ->  12+4=16

     1.txt   -> 5   ->  8   ->  12+8=20

     3a.jpg  -> 6   ->  8   ->  12+8=20

   abcdef.jpg-> 10  ->  12  ->  12+12=24

d_type:

enum

  {

    DT_UNKNOWN = 0,  -> 未知类型

    DT_FIFO = 1,   -> 管道文件

    DT_CHR = 2,    -> 字符设备文件

    DT_DIR = 4,    -> 目录文件

    DT_BLK = 6,    -> 块设备

    DT_REG = 8,   -> 普通文件

    DT_LNK = 10,  -> 链接文件

    DT_SOCK = 12,  -> 套接字文件

  };

5. 重置目录指针?  -> rewinddir()  -> man 3 rewinddir

  #include <sys/types.h>

  #include <dirent.h>

 void rewinddir(DIR *dirp);

  dirp: 目录流指针

  返回值:无

#include <sys/types.h>

#include <dirent.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

       //1. 打开目录

       DIR *dp = opendir("./dir");

       if(dp == NULL)

              printf("opendir error! ");

       //2. 切换到目录下

       chdir("./dir");

       //3. 读取目录中每一项

       struct dirent *ep = NULL;

       while(1)

       {

              ep = readdir(dp);

              if(ep == NULL)  //读取完毕

                     break;

              if(ep->d_name[0] == '.')

                     continue;

              printf("ep->d_ino = %d ",(int)ep->d_ino);     

              printf("ep->d_off = %d ",(int)ep->d_off);

              printf("ep->d_reclen = %d ",ep->d_reclen);

              printf("ep->d_type = %d ",ep->d_type);

              printf("ep->d_name = %s ",ep->d_name);

              printf("================================ ");     

       }

       //4. 关闭目录

       closedir(dp);

       return 0;

}

作业:

有一个目录,里面很多张800*480 bmp格式图片,执行程序后,先显示第一张图片,如果点击左边松手,则显示上一张,如果右边松手,下一张。要求五轮目录有多少张图片,程序都可以正常运行。

原文地址:https://www.cnblogs.com/zjlbk/p/11265525.html