怎么把 bytearray 转换为二进制数据?

2017-11-27 18:03:27 +08:00
 PHizing
我写了个 python 程序,把一个生成好的字典( key-value )发到 redis。
value 数据,本来是一个整型列表,不过我自定义了压缩函数,把它转换成了一个 bytearray 数据,然后通过 redis 的 hmset 把字典存到了 redis。

但我用 redis 命令到 redis 服务器上去看时,value 数据是类似下面的:
"bytearray(b'\\x85\\x88\\xde\\xbe\\x01\x11)'"
完全跟我想要放上去的数据不一致。这看着就像一个 16 进制转换成的 ascii 码,而我想要放到 redis 的是一个二进制的字节流,类似"0x85 0x88 0xde 0xde"这样的,好方便被 C++程序读下来再解压。

请问下,怎样把 bytearray 转成二进制字节?多谢。
5129 次点击
所在节点    Python
14 条回复
tangweihua163
2017-11-27 18:25:58 +08:00
这不就是二进制流么
catror
2017-11-27 18:33:37 +08:00
这不就是二进制流么+1
PHizing
2017-11-27 18:37:33 +08:00
不是哦。
我希望 C++拿到的是一堆字节,这些字节没有“\\”这样的东西。现在明显是可显示的字符数据。
Kisesy
2017-11-27 19:00:11 +08:00
bytes(bytearray(xxxxxx))
justou
2017-11-27 19:49:21 +08:00
你保存的是 python 字典, 它的值是个 bytearray 对象, 不论是 bytes 还是 bytearray, 你把它以字符串形式输出来的时候都是那样显示的(这个是由它的__str__方法决定的), 至于你说的要传递给 C++处理, 意思是要传递一个 python 的 bytes 或 bytearray 给 C++么? 这有很多方法, 通过 Cython 搭桥是最直观简单的.

你想的大概是这样的 C++可以直接处理的二进制数据:

from struct import pack
bin_val= bytearray("123abc 呵呵", encoding='utf-8')
with open("test_bin.bin", 'bw') as fout:
fout.write(pack('%ss'%len(bin_val), bin_val))

随便找个 hex editor 检查下 test_bin 就很清楚了

https://docs.python.org/3/library/struct.html#module-struct
neoblackcap
2017-11-27 20:00:01 +08:00
我是觉得楼主你用法错了,你存进去 redis 的数据就应该用序列化,比如用 json 这样的格式,要不然,你 C++的程序如何解析呢?,存进去的时候序列化就好了,想简单就用 json 这个标准库吧。本身 redis 里面存的就是二进制,你 C++的程序去读是一样的,你看到"bytearray(b'\\x85\\x88\\xde\\xbe\\x01\x11)'" 只不过是你用 ascii 编码解码得到的结果。
要正确地序列话与反序列化!
dbow
2017-11-27 20:10:49 +08:00
用 msgpack, json 占用空间太大, 浪费内存。
ipwx
2017-11-27 20:26:26 +08:00
bytearray 本来就是二进制。

问题出在你存 redis 的那段代码。贴出来看看?
koint
2017-11-27 21:06:32 +08:00
我感觉应该是 redis 存入时的问题,redis 存入二进制需要使用 SETBIT key offset value 这样按照位的形式来设置

但是按照描述应该是操作 redis 的封装方法把字典中的 bytearray 当做了字符串 所以调用了魔法方法 __str__() 导致存入了 字符串显示形式的 bytearray

如果一定要在 redis 存二进制的话可能要自己写一个方法按位存储
不过我感觉存 json 或者刚才楼上提到的 msgpack 比较好,个人看法,不喜勿喷😂
PHizing
2017-11-28 08:50:08 +08:00
综合大家的意见,说明下:
1. redis 的数据,一直以来都是给 C++程序使用,C 写 C 读。不过我改了一个子功能,把 C 写的改为 python 写,所以序列化的代码是不能改为 msgpack 或者是 json 的。
2. 序列化的代码,类似于一个整型数组,变成 byte 字节流:
类 C 代码: int a[100] = {1, 2, 3....}
PHizing
2017-11-28 08:55:54 +08:00
类 C 代码: int a[100] = {1, 2, 3....};
char *b = new char[1000];
char *pb = b
for (i = 0; i < 99; ++i)
char *buffer = NULL;
size = convert_byte(a[i], buffer);
memcpy(pb, buffer, size)
pb += size
PHizing
2017-11-28 09:04:19 +08:00
3. python 发布数据到 redis 代码:
redis_dict = dict()
for pid, rids in result.items():
redis_dict[pid] = 前面的序列化代码,把 rids 这个整型列表传进去,得到一个 bytearray 的 buffer

r = redis.Redis(host, port, db)
r.hmset(REDIS_TABLE, redis_dict)

4. 我也不知道是不是哪里用错了,初次开发这种底层的数据,还没搞清楚 bytes, bin, bytearray 这些数据的区别
5. 我想要的是字节流,不是那种看着可读的字符串。改了好几次代码,到 redis 上看到的是'\x85\x86'这样的,我就知道又不对。实际上,之前 C++写到 redis 的数据,用 hget REDIS_TABLE pid 去看,全部是乱码,那才是对的。
turnrut
2017-11-28 11:48:07 +08:00
把那些乱码复制出来然后查看下他们的二进制表示,再跟 python 输出的文件对比下
linux 下可以使用 od 命令 "echo test | od -tx" (这个选项是输出 16 进制的,毕竟纯 2 进制可读性太差)
PHizing
2017-11-29 12:02:04 +08:00
@Kisesy 你的方法可以,我试了,再转成 bytes 在 redis 上就看到了二进制数据。多谢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/409989

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX