将二进制数据转换为网页安全文本及其反向 - Python
我想把一个二进制文件(比如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 个回答
你的文档参考的是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)
就可以了。
你应该使用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
。
你的代码看起来有点复杂。试试这个:
#!/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
看起来最简单——只需把它变成一个字符串,处理一下,然后再转换回来。