我有任意二进制数据。我需要将它存储在一个需要有效UTF8的系统中。它永远不会被解释为文本,我只需要将其放在那里并能够检索它并重新构建我的二进制数据。
显然base64会起作用,但我不能那么多通货膨胀。
如何在python 2.7中轻松实现这一目标?
答案 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%。
如果您的数据有任何结构,那么zlib将其压缩为Martijn建议,可能会减小其大小。
答案 2 :(得分:0)
如果您的应用程序确实要求您能够以图形可区分的形式表示256个不同的字节值,那么您实际需要的只是256个Unicode代码点。问题解决了。
ASCII代码33-127是不费吹灰之力的,Unicode代码点160-255也是代表自己的好选择,但你可能想要排除一些难以区分的代码(如果你想要OCR或人类来处理它们)可靠,áåä等可能太相似了)。从可以用两个字节表示的代码点集合中选择其余部分 - 相当大的集合,但同样,在大多数渲染中,其中许多代码与其他字形在图形上无法区分。
此方案不会尝试任何形式的压缩。我想如果这是一个问题,你可以通过在编码之前压缩数据来获得更好的结果。