将二进制数据转换为网页安全文本及其反向 - Python

0 投票
4 回答
1613 浏览
提问于 2025-04-17 04:51

我想把一个二进制文件(比如jpg、mp3等)转换成网页安全的文本,然后再把它转换回二进制数据。我查了一些模块,感觉快成功了,但总是出现数据损坏的问题。

在查看了binascii的文档后,我想出了这个方法:

from binascii import *
raw_bytes = open('test.jpg','rb').read()
text = b2a_qp(raw_bytes,quotetabs=True,header=False)
bytesback = a2b_qp(text,header=False)
f = open('converted.jpg','wb')
f.write(bytesback)
f.close()

但是当我尝试打开converted.jpg时,发现数据又损坏了 :-/

我还试过用b2a_base64处理57个长的二进制数据块。我把每个数据块转换成字符串,然后把它们拼接在一起,最后再用a2b_base64转换回去,结果又出现了损坏。

有没有人能帮帮我?我对字节和文件格式的细节不是很了解。我是在Windows上用Python,如果这对处理\r\n有影响的话。

4 个回答

1

你的文档参考的是Python 3.0.1。其实没有什么好理由去用Python 3.0。你应该使用3.2或者2.7。你到底在用哪个版本呢?

建议: (1) 把bytes改成raw_bytes,这样可以避免和内置的bytes搞混; (2) 在你的测试脚本中检查raw_bytes是否等于bytes_back; (3) 虽然你的测试可以用quoted-printable,但对于二进制数据来说效率很低,建议用base64。

更新:Base64编码是每3个输入字节会产生4个输出字节。你的base64代码在处理56字节的数据块时会出问题,因为56不是3的整数倍;每个数据块需要填充到3的倍数。然后你把这些数据块连接起来再尝试解码,这样肯定是不行的。

你的数据块循环可以写得更好,像这样:

output_string = ''.join(
    b2a_base64(raw_bytes[i:i+57]) for i in xrange(0, xrange(len(raw_bytes), 57)
    )

总之,分块处理比较慢而且没必要;直接用b2a_base64(raw_bytes)就可以了。

1

你应该使用base64编码,而不是quoted printable编码。可以使用b2a_base64()a2b_base64()这两个函数。

对于像图片这样的二进制数据,quoted printable编码会变得非常大。在这种编码中,每个二进制(非字母数字字符)代码都会被转换成=HEX的形式。它适合用于主要由字母和数字组成的文本,比如电子邮件的主题。

而base64编码对于主要是二进制数据的情况要好得多。它的工作原理是先取第一个字节的6位,然后取第一个字节的最后2位和第二个字节的4位,依此类推。你可以通过编码文本末尾的=符号来识别这种编码(有时会用其他字符)。

举个例子,我用一个大小为271,700字节的.jpeg文件来说明。在quoted printable编码下,它的大小是627,857字节,而在base64编码下,它的大小是362,269字节。quoted printable的大小取决于数据类型:只有字母的文本大小不会改变。base64的大小计算公式是orig_size * 8 / 6

1

你的代码看起来有点复杂。试试这个:

#!/usr/bin/env python

from binascii import *
raw_bytes = open('28.jpg','rb').read()
i = 0
str_one = b2a_base64(raw_bytes) # 1
str_list = b2a_base64(raw_bytes).split("\n") #2

bytesBackAll = a2b_base64(''.join(str_list)) #2
print bytesBackAll == raw_bytes #True #2

bytesBackAll = a2b_base64(str_one) #1
print bytesBackAll == raw_bytes #True #1

标记为 #1#2 的行是可以互相替代的。对我来说,#1 看起来最简单——只需把它变成一个字符串,处理一下,然后再转换回来。

撰写回答