将任意二进制数据存储在仅接受有效UTF8的系统上

时间:2014-08-30 14:31:36

标签: python python-2.7 unicode utf-8

我有任意二进制数据。我需要将它存储在一个需要有效UTF8的系统中。它永远不会被解释为文本,我只需要将其放在那里并能够检索它并重新构建我的二进制数据。

显然base64会起作用,但我不能那么多通货膨胀。

如何在python 2.7中轻松实现这一目标?

3 个答案:

答案 0 :(得分:4)

您将 使用 ASCII字符来表达您的数据。在使二进制数据适合于也是UTF-8安全的可打印文本方面,使用Base64是最有效的方法(在Python标准库中可用)。当然,它需要33%的空间来表达相同的数据,但其他方法需要更多额外的空间。

你可以将它与 compression 结合起来,以限制它将占用多少空间,但是使压缩成为可选(标记数据),并且只有在数据变得更小时才实际使用它

import zlib
import base64

def pack_utf8_safe(data):
    is_compressed = False
    compressed = zlib.compress(data)
    if len(compressed) < (len(data) - 1):
        data = compressed
        is_compressed = True
    base64_encoded = base64.b64encode(data)
    if is_compressed:
        base64_encoded = '.' + base64_encoded
    return base64_encoded

def unpack_utf8_safe(base64_encoded):
    decompress = False
    if base64_encoded.startswith('.'):
        base64_encoded = base64_encoded[1:]
        decompress = True
    data = base64.b64decode(base64_encoded)
    if decompress:
        data = zlib.decompress(data)
    return data

'.'字符不是Base64字母表的一部分,因此我在此处使用它来标记压缩数据。

您可以从Base64编码数据的末尾进一步削减1或2个=填充字符;这些可以在解码时重新添加(将'=' * (-len(encoded) * 4)添加到结尾),但我不确定这是值得的。

您可以通过切换到Base85 encoding,二进制数据的4比5 ASCII安全编码来实现进一步节省,因此开销为20%。对于Python 2.7,这只能在外部库中使用(Python 3.4 added it to the base64 library)。您可以在2.7:

中使用python-mom project
from mom.codec import base85

并用base64.b64encode()base64.b64decode()来代替所有base85.b85encode()base85.b85decode()来电。

如果您100%确定路径中的任何内容都不会将您的数据视为 text (可能会更改行分隔符,或解释和更改其他控制代码),您还可以使用Base128编码,将开销减少到14.3%(每7个字节8个字符)。但是,我不能为您推荐一个可以安装pip的Python模块;有一个GitHub hosted module,但我没有测试过。

答案 1 :(得分:0)

您可以将字节解码为8859-1数据,这将始终生成有效的Unicode字符串。然后你可以将它编码为UTF8:

utf8_data = my_bytes.decode('iso8859-1').encode('utf8')

平均而言,一半数据将在0-127范围内,即UTF8中的一个字节,一半数据将在128-255范围内,即UTF8中的两个字节,因此您的结果将是比输入数据大50%。

如果您的数据有任何结构,那么zl​​ib将其压缩为Martijn建议,可能会减小其大小。

答案 2 :(得分:0)

如果您的应用程序确实要求您能够以图形可区分的形式表示256个不同的字节值,那么您实际需要的只是256个Unicode代码点。问题解决了。

ASCII代码33-127是不费吹灰之力的,Unicode代码点160-255也是代表自己的好选择,但你可能想要排除一些难以区分的代码(如果你想要OCR或人类来处理它们)可靠,áåä等可能太相似了)。从可以用两个字节表示的代码点集合中选择其余部分 - 相当大的集合,但同样,在大多数渲染中,其中许多代码与其他字形在图形上无法区分。

此方案不会尝试任何形式的压缩。我想如果这是一个问题,你可以通过在编码之前压缩数据来获得更好的结果。