(一)要做什么

之前有这么一个需求,是要把一个二进制文件里面的数据,转换成 C 代码里面的数组,可以看之前的一篇文章:

NUC980 运行 RT-Thread 驱动 SPI 接口 OLED 播放 badapple

于是用 python 把这个功能给做了出来,原理非常简单,代码量也很小。

所处理的文件大小如下,用一个编辑器以二进制形式打开的话,一行16字节,一共 336448 行。

(二)实现功能

上代码,Show me your code.Talk is cheap.

import os
import time
start_time = time.time()
fileinfo = os.stat("badapple.bin")
line = fileinfo.st_size / 16
print(line)

首先导入 os、time 模块,os 模块用户获取所处理文件的大小,生成的头文件里面的数组每 16 字节一行,time 模块用于统计程序所使用时间,上述代码运行结果为:

336648 行,正好与之前看到的一致。

然后定义一个变量,用来存储最终的数据:

target = "#ifndef __BADAPPLE_H__ \n#define __BADAPPLE_H__\n\n const uint8_t badapple[] = \n{\n"

然后打开文件 badapple.bin,以二进制、只读方式打开,每次读取一字节,然后转换成二进制,与 0x 组成一个字节数据,保存到上述字符串中,每处理完 16 字节添加换行,处理完后关闭文件,代码如下:

f = open("badapple.bin", "rb")
for l in range(int(line)):
for j in range(16):
data = f.read(1)
he = "0x" + data.hex()
target = target + he + ","
print(l)
target = target + "\n" target = target + "}; \n\n#endif\n"
print(target)
f.close()

由于全部数据有 30 多万行,不好测试,先只处理 badapple.bin 文件中的前 15 行,来测试下代码有没有问题,把上面代码中的第二行改为:

for l in range(15):

运行结果为:

看上去是可以的,然后实现把转换出来的数据保存到文件中,并加上获取运行改代码所花时间,代码如下:

file = open("badapple.h","w")
file.write(target)
file.close()
end_time = time.time()
print(end_time - start_time)

运行结果为:

所生成的文件为:

从所生成的文件来看,算是大功告成了,把所需处理行数改为实际文件的行数,就完成了。

然而,我还是图样图森破啊,我以为我在第二层,其实我在第五层。

第一次运行的时候,跑了几十分钟,停了,感觉所花时间大大久了,

出于对自己写的代码负责的态度,第二天下午 3 点多的时候,再次把这代码跑了起来,可是到了6点多还是没跑完,又中途结束了,

很好奇,究竟需要多长时间来跑,第三天,一早上就把代码跑了起来,结果是到了下午 6 点多,差不多 7 点才跑完,来看下运行的最后结果:

从数字来看,30545 秒,感觉也不是很大,可是转换为小时的话:

30545 / 60 / 60 = 8.4

居然达到了 8.4 个小时,这是生成的文件:

(三) 优化

要这么久时间来跑肯定是不实际的,修改下代码,之前是一个字节一个字节从文件里面读出来,这次改为每次从文件中读取 16 字节,转换,然后再读取16字节,知道结束,代码如下:

target = "#ifndef __BADAPPLE_H__ \n#define __BADAPPLE_H__\n\n const uint8_t badapple[] = \n{\n"

line = fileinfo.st_size / 16
print(line)
for l in range(int(line)):
data = f.read(16)
he = ""
for da in data:
he = he + hex(da) + ","
print(l)
target = target + he + "\n" target = target + "}; \n\n#endif\n"

运行下,最后结果为:

2165 秒,大概是 36 分钟,也还是有点长。

再改改,对比下这 2 中方法,第二种是每次读出来的字节数是第一种的16倍,速度明显提升了,可以看出时间是损耗在从文件读取数据,那如果一次性把所用数据从文件种读取出来会不会更快呢?试了下,代码改为:

f = open("badapple.bin", "rb")
target = "#ifndef __BADAPPLE_H__ \n#define __BADAPPLE_H__\n\n const uint8_t badapple[] = \n{\n"
dat = f.read()
print(type(dat))
f.close()
whole = dat.__len__()
line = int(whole / 16)
for i in range(line):
temp = dat[i*16:i*16+16]
he = ""
for da in temp:
he = he + hex(da) + ","
target = target + he + "\n"
print(i) target = target + "}; \n\n#endif\n"

运行了下,结果为:

2340 秒,居然比第二种方法还长。

还有什么方法可以改进呢?现在时间估计是花在转换上面,在转换上有没有改进方法,目前还没找出来。

(四)做的更通用

那是不是说这段代码就完全没用,非也非也,用来转换小点的文件还是可以的,这不止可以转换二进制文件,还可以转换其他任何文件,比如图片、字库等,以下是转换一张图片运行的结果:

为了更通用,修了下代码,如下:

运行的时候需要传个参数,这个参数就是要处理的文件,最后生成的头文件、头文件里数组命名都是根据处理的文件的名字来设定的,运行过程中还显示处理进度,最后显示处理所花时间。比如把上述代码保存到文件 hex2header.py,比如要转换的文件为 test.pdf,用法为:

python hex2header.py test.pdf

实际运行为:

这示例转换了一个 323K 大小的 pdf 文件,每行 16 字节的话,大概 20653 行,花了6.4 秒的时间。

转载请注明出处:https://www.cnblogs.com/halin/

最新文章

  1. C语言实现2个大数相加。
  2. ((uchar*)(Img1->imageData + Img1->widthStep*pt.y))[pt.x] 的 具体含义
  3. hashchange事件的认识
  4. 几款开源的图形化Redis客户端管理软件
  5. sourceInsight使用技巧,持续更新中~~~
  6. 剑指offer——替换字符串
  7. Fedora 21 安装QQ国际版
  8. thinkphp框架dump友好调试输出函数
  9. Android ActionBar详解(三):ActionBar实现切换Tabs标签
  10. 对163k地方门户网站系统QQ互联功能修改
  11. knockout简单实用教程3
  12. MySQL注入与防御(排版清晰内容有条理)
  13. [经验分享] OSCP 渗透测试认证
  14. 洛谷P1073 最优贸易
  15. SkylineGlobe 如何实现二次开发加载KML文件
  16. linux系统web站点设置-http基础设置
  17. 乘风破浪:LeetCode真题_028_Implement strStr()
  18. Linux iptables常用命令的使用
  19. HDU Bomb Game 3622 (2-Sat)
  20. 如何在Qt Creator中创建pri文件,以及pri文件的说明

热门文章

  1. python 运算及注释
  2. Web网站实现用户认证访问(加密访问)
  3. TEB 系统综合误差
  4. Chrome版本与chromedriver版本映射表
  5. 服务器RAID配置
  6. 使用Mybatis插件 PageHelper 模拟百度分页(Day_20)
  7. 用华为MindSpore框架训练数据库类型的数据集
  8. ThinkPHP无限级分类(递归)
  9. 面试侃集合 | SynchronousQueue公平模式篇
  10. linux ( crontab 定时任务命令)