zoukankan      html  css  js  c++  java
  • 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格式图片,执行程序后,先显示第一张图片,如果点击左边松手,则显示上一张,如果右边松手,下一张。要求五轮目录有多少张图片,程序都可以正常运行。

  • 相关阅读:
    IOS GameCenter验证登陆
    BZOJ 1597: [Usaco2008 Mar]土地购买 斜率优化
    Hihocoder #1602 : 本质不同的回文子串的数量 manacher + BKDRhash
    HDU 5343 MZL's Circle Zhou 后缀自动机+DP
    HDU 6208 The Dominator of Strings 后缀自动机
    SPOJ SUBLEX
    SPOJ LCS2
    .NET平台技术体系梳理+初学者学习路径推荐+我们的愿景与目标
    扑克模拟,牌型判断java版
    一道综合练习题实践list及dictionary集合类
  • 原文地址:https://www.cnblogs.com/zjlbk/p/11265525.html
Copyright © 2011-2022 走看看