做开发,尤其是嵌入式开发,要不过去过去曾经,要不现在,或者将来一定会遇到十六进制字符串和二进制文件之间转换的操作。

像这样的情形:

  1. 有一个十六进制字符串,需要转换为二进制文件
  2. 有一个二进制文件,需要转换为十六进制数组
  3. 有一个十六进制数组,需要转换为二进制文件;
  4. 有一个二进制文件,需要转换为十六进制字符串;

最多就是前两种情形。不管你是不是经常遇到,反正我是。

以前到处搜,没找到中意的,后来干脆自己用python写了个脚本将二进制转数组。到后来发现,都是浪费时间,linux自带工具就能满足这样的需求,甚至更多。

好吧,废话不多说了。一句话,命令行工具xxd能让你实现这种自由。要是觉得太啰嗦,还请直接转到第7节看总结。

1. 十六进制字符串转换为二进制文件

  • 例一

我有一个十六进制字符串,包含字母数字大小写,想转换成二进制文件。

# 字符串: ABCDEF0123456789abcdef0123456789

# 1. 转换
$ echo -n "ABCDEF0123456789abcdef0123456789" | xxd -r -ps > test11.bin

# 2. 检查
$ xxd -g 1 test11.bin
0000000: ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89  ....#Eg.....#Eg.
  • 例二

例一中的情形太简单了,上个复一点的,这次是完整的十六进制字符串,字符带有0x前缀,还有空格,想转换成二进制文件。

# 字符串: 0xAB 0xCD 0xEF 0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF 0x01 0x23 0x45 0x67 0x89

# 转换
$ echo -n "0xAB 0xCD 0xEF 0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF 0x01 0x23 0x45 0x67 0x89" | xxd -r -ps > test12.bin

# 检查
$ xxd test12.bin
0000000: abcd ef01 2345 6789 abcd ef01 2345 6789  ....#Eg.....#Eg.
  • 例三

升级版,这次的字符串中不仅有0x前缀,带空格,还有逗号","分割,一样不在话下:

# 字符串: "0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89"

# 转换
$ echo -n "0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89" | xxd -r -ps > test13.bin

# 检查
$ xxd test13.bin
0000000: abcd ef01 2345 6789 abcd ef01 2345 6789  ....#Eg.....#Eg.

就一条命令,带有字母数字大小写,带空格0x前缀和逗号的字符串,通通一行搞定,就问你服不服。

2. 二进制文件转换成十六进制数组

用到这个操作的地方实在是太多了,常常需要将各种点阵字库,各种图片,各种固件转换成代码。

So easy! 一秒搞定!

  • 例四

把前面例一中的二进制文件转换成数组。

方式一:

# 文件
$ xxd -g 1 test11.bin
0000000: ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89  ....#Eg.....#Eg.

# 数组
$ xxd -i test11.bin
unsigned char test11_bin[] = {
  0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
  0x23, 0x45, 0x67, 0x89
};
unsigned int test11_bin_len = 16;

方式二:

# 文件
$ xxd -g 1 test11.bin
0000000: ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89  ....#Eg.....#Eg.

# 数组
$ xxd -i < test11.bin
  0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
  0x23, 0x45, 0x67, 0x89

这两种方式有点小差别,看出来区别在哪里了吗?不管怎样,就问你爽不爽?

3. 十六进制数组转换成二进制文件

  • 例五

其实这种方式在例三中已经说过了,对头不?

# 从数组中拿到的字符串
$ echo -n "  0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
  0x66, 0x77, 0x88, 0x99, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
  0xAB, 0xCD, 0xEF, 0x98, 0x76, 0x54, 0x32, 0x10
" | xxd -r -ps > test31.bin

# 检查文件
$ hexdump -Cv test31.bin
00000000  aa bb cc dd ee ff 00 11  22 33 44 55 66 77 88 99  |........"3DUfw..|
00000010  01 23 45 67 89 ab cd ef  ab cd ef 98 76 54 32 10  |.#Eg........vT2.|
00000020

4. 二进制文件转换为十六进制字符串

  • 例六

我有个二进制文件,想转换成对应的字符串。

就是把前面例一中的二进制文件还原成字符串

# 二进制文件
$ xxd -g 1 test11.bin
0000000: ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89  ....#Eg.....#Eg.

# 转换成小写字符串
$ xxd -ps test11.bin
abcdef0123456789abcdef0123456789

# 转换成大写字符串
$ xxd -ps -u test11.bin
ABCDEF0123456789ABCDEF0123456789

5. 更多骚操作,十六进制转二进制位串

  • 例七,查看文件的二进制位串
$ xxd -g 1 test11.bin
0000000: ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89  ....#Eg.....#Eg.
$ xxd -b test11.bin
0000000: 10101011 11001101 11101111 00000001 00100011 01000101  ....#E
0000006: 01100111 10001001 10101011 11001101 11101111 00000001  g.....
000000c: 00100011 01000101 01100111 10001001                    #Eg.

$ xxd -g 1 -c 8 test11.bin
0000000: ab cd ef 01 23 45 67 89  ....#Eg.
0000008: ab cd ef 01 23 45 67 89  ....#Eg.
rocky@guyongqiangx:/public/xxd$ xxd -b -c 8 test11.bin
0000000: 10101011 11001101 11101111 00000001 00100011 01000101 01100111 10001001  ....#Eg.
0000008: 10101011 11001101 11101111 00000001 00100011 01000101 01100111 10001001  ....#Eg.

6. 不能再爽了,还能直接修改二进制文件

  • 例八,修改二进制文件

直接以指定偏移量的方式修改文件,下面这个命令将0x12开始的4个字节替换为"0xAA 0xBB 0xCC 0xDD":

# 修改前
$ xxd test31.bin
0000000: aabb ccdd eeff 0011 2233 4455 6677 8899  ........"3DUfw..
0000010: 0123 4567 89ab cdef abcd ef98 7654 3210  .#Eg........vT2.

# 替换0x12开始的4个字节为 AA BB CC DD
$ echo -n "0012: AABBCCDD" | xxd -r - test31.bin

# 修改后
$ xxd test31.bin
0000000: aabb ccdd eeff 0011 2233 4455 6677 8899  ........"3DUfw..
0000010: 0123 aabb ccdd cdef abcd ef98 7654 3210  .#..........vT2.

命令echo -n "0012: AABBCCDD" | xxd -r - test31.bin中有个小小的-,千万不要漏掉了。

还有,修改前记得要备份!哭的时候,不要说我没提醒过,哈哈哈~~

7. 总结

  • 十六进制字符串转换成二进制文件
$ echo -n "ABCDEF0123456789abcdef0123456789" | xxd -r -ps > test11.bin
  • 二进制文件转换成十六进制数组
$ xxd -i test11.bin
unsigned char test11_bin[] = {
  0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
  0x23, 0x45, 0x67, 0x89
};
unsigned int test11_bin_len = 16;
  • 二进制文件转换成十六进制字符串
$ xxd -ps test11.bin
abcdef0123456789abcdef0123456789

掌握了这3条命令,十六进制和二进制转化,你自由了。

剩下的时间可用来泡妞,可用来划水,可用来摸鱼,还可以用来解更多的bug,这一切的一切,难道不香吗?

xxd工具,你值得拥有。


最近会重新开始更新公众号,所以来一波硬广。

洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。

所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:

  • 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。
  • 一个Android OTA的讨论组,请说明加Android OTA群。
  • 一个git和repo的讨论组,请说明加git和repo群。

在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意:

收钱码

洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:

公众号

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐