(一)要做什么

之前有这么一个需求,是要把一个二进制文件里面的数据,转换成 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/

使用 python 把一个文件生成 C 语言中的数组并保存到头文件中的更多相关文章

  1. python脚本将json文件生成C语言结构体

    1.引言 以前用过python脚本根据excel生成相关C语言代码,其实本质就是文件的读写,主要是逻辑问题,这次尝试将json文件生成C语言的结构体. 2.代码 这是一个json文件,生成这个结构体的 ...

  2. 利用POI抽取word中的图片并保存在文件中

    利用POI抽取word中的图片并保存在文件中 poi.apache.org/hwpf/quick-guide.html 1.抽取word doc中的图片 package parse; import j ...

  3. 当Android工程中提示你找不到头文件,但你已经设置头文件路径了

    虽然在Android.mk文件中,配置了LOCAL_C_INCLUDES路径,但是工程中的红色叉号一直提示找不到头文件 这时,你在工程树目录中展开Includes项,捣鼓捣鼓,重新build下,或许就 ...

  4. 为Python编写一个简单的C语言扩展模块

    最近在看pytorh方面的东西,不得不承认现在这个东西比较火,有些小好奇,下载了代码发现其中计算部分基本都是C++写的,这真是要我对这个所谓Python语音编写的框架或者说是库感觉到一丢丢的小失落,细 ...

  5. [转]用Python做一个自动生成读表代码的小脚本

    写在开始(本片文章不是写给小白的,至少你应该知道一些常识!) 大家在Unity开发中,肯定会把一些数据放到配置文件中,尤其是大一点的项目,每次开发一个新功能的时候,都要重复的写那些读表代码.非常烦.来 ...

  6. Python写一个批量生成账号的函数

    批量生成账户信息,产生的账户由@sina.com结尾,长度由用户输入,产生多少条也由用户输入,用户名不能重复,用户名必须由大写字母.小写字母和数字组成. def Users(num,len): # n ...

  7. python写一个能生成三种一句话木马的脚本

    代码: import time import os from threading import Thread import optparse def aspyijuhua(): try: juy=op ...

  8. Python强化训练笔记(七)——使用deque队列以及将对象保存为文件

    collections模块中的deque对象是一个队列,它有着正常队列的先进先出原则.我们可以利用这个对象来实现数据的保存功能. 例如,现有一个猜数字大小的游戏,系统开始会随机roll点一个0-100 ...

  9. Python爬虫根据关键词爬取知网论文摘要并保存到数据库中【入门必学】

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:崩坏的芝麻 由于实验室需要一些语料做研究,语料要求是知网上的论文摘要 ...

随机推荐

  1. Scala 安装与配置

    安装准备 由于 Scala 运行于 Java 平台,因此 Scala 之前需要确保系统安装 JDK Windows 中安装 Scala 1. 下载 scala-2.11.2.msi 安装包 点击安装文 ...

  2. Linux进阶之进程管理

    本节内容 1.进程管理 2.ps 3.uptime 4.top 5.ss -tnl------ lsof -i :22 一. 进程管理的概念 程序:二进制文件,静态 /bin/date,/usr/sb ...

  3. 电压笔DIY

    电压逻辑笔 http://www.cirmall.com/circuit/2279/detail?3#/details http://www.cirmall.com/circuit/7543/CD45 ...

  4. centos7 搭建 nginx web服务 反代理

    Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. ...

  5. Day30 BigInteger和BigDecimal

    BigInteger与BigDecimal BigInteger类 Integer类作为int的包装类,能存储的最大整型值为2 31-1,Long类也是有限的, 最大为2 63-1.如果要表示再大的整 ...

  6. 【补档_STM32单片机】脉搏波采集显示硬件设计

    一.脉搏波简介 ​ 脉搏一般情况下指的都是动脉脉搏.每分钟的脉搏次数称为脉率,正常情况下与心率是一致的.心脏的一次收缩和舒张成为一个心动周期.在每个心动周期内,心室的收缩和舒张会引起脉内压力的周期性波 ...

  7. synchronized 的超多干货!

    前言 synchronized 这个关键字的重要性不言而喻,几乎可以说是并发.多线程必须会问到的关键字了.synchronized 会涉及到锁.升级降级操作.锁的撤销.对象头等.所以理解 synchr ...

  8. CUDA C++编程接口:编译

    CUDA C++编程接口:编译 一.概述 CUDA C++为熟悉C++编程语言的用户提供了一个简单的路径,以方便地编写程序以执行该设备. 它由一组最小的扩展到C++语言和运行库. 在编程模型中引入了核 ...

  9. Kubernetes 实战——配置应用(ConfigMap、Secret)

    配置容器化应用的方式:①命令行参数:②环境变量:③文件化配置 一.向容器传递命令行参数或环境变量 这两种方式在 Pod 创建后不可被修改 1. 在Docker中定义命令与参数 ENTRYPOINT:容 ...

  10. 【SQLite】教程06-SQLite表操作

    创建表: CREATE TABLE 语句用于在任何给定的数据库创建一个新表.命名表.定义列.定义每一列的数据类型 查看表: 详细查看表: 重命名表: 删除表: 创建表并添加7条记录(第七条记录用了第二 ...