V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
PHizing
V2EX  ›  Python

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

  •  
  •   PHizing · 2017-11-27 18:03:27 +08:00 · 5300 次点击
    这是一个创建于 2588 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我写了个 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 转成二进制字节?多谢。
    14 条回复    2017-11-29 12:02:04 +08:00
    tangweihua163
        1
    tangweihua163  
       2017-11-27 18:25:58 +08:00
    这不就是二进制流么
    catror
        2
    catror  
       2017-11-27 18:33:37 +08:00 via Android
    这不就是二进制流么+1
    PHizing
        3
    PHizing  
    OP
       2017-11-27 18:37:33 +08:00
    不是哦。
    我希望 C++拿到的是一堆字节,这些字节没有“\\”这样的东西。现在明显是可显示的字符数据。
    Kisesy
        4
    Kisesy  
       2017-11-27 19:00:11 +08:00
    bytes(bytearray(xxxxxx))
    justou
        5
    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
        6
    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
        7
    dbow  
       2017-11-27 20:10:49 +08:00
    用 msgpack, json 占用空间太大, 浪费内存。
    ipwx
        8
    ipwx  
       2017-11-27 20:26:26 +08:00
    bytearray 本来就是二进制。

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

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

    如果一定要在 redis 存二进制的话可能要自己写一个方法按位存储
    不过我感觉存 json 或者刚才楼上提到的 msgpack 比较好,个人看法,不喜勿喷😂
    PHizing
        10
    PHizing  
    OP
       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
        11
    PHizing  
    OP
       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
        12
    PHizing  
    OP
       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
        13
    turnrut  
       2017-11-28 11:48:07 +08:00
    把那些乱码复制出来然后查看下他们的二进制表示,再跟 python 输出的文件对比下
    linux 下可以使用 od 命令 "echo test | od -tx" (这个选项是输出 16 进制的,毕竟纯 2 进制可读性太差)
    PHizing
        14
    PHizing  
    OP
       2017-11-29 12:02:04 +08:00
    @Kisesy 你的方法可以,我试了,再转成 bytes 在 redis 上就看到了二进制数据。多谢。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1018 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:41 · PVG 03:41 · LAX 11:41 · JFK 14:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.