设为首页 收藏本站
查看: 932|回复: 0

[经验分享] 【Python】二进制文件与Base64编码文本文件转换

[复制链接]

尚未签到

发表于 2017-5-8 10:36:58 | 显示全部楼层 |阅读模式
前面的话
Python内置的base64模块,在这里http://docs.python.org/library/base64.html?highlight=base64#base64,包括b64encodeb64decodeurlsafe_b64decode等,可以满足包括URL在内的文本编码需要。但是在用base64.encode编码二进制文件的时候,发现编码不完整,只有部分文件被编码了,base64.decode解码出来文件错误。可能是base64模块用来出来文本的?仔细分析发现,是忘记用二进制模式打开文件了。但是,自己实现base64模块基本功能也不是什么难事,不是要重复发明轮子,仅作为学习pythonbase64的练习。
用内置 base64模块转换二进制文件与base64编码文本文件方法如下:

import base64
fin = open(r"D:\2.zip", "rb")
fout = open(r"D:\2.x.txt", "w")
base64.encode(fin, fout)
fin.close()
fout.close()
fin = open(r"D:\2.x.txt", "r")
fout = open(r"D:\2.x.zip", "wb")
base64.decode(fin, fout)
fin.close()
fout.close()
 
Base64介绍
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括MIMEemailemail via MIME, XML中存储复杂数据。
转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲区中剩下的bit0补足。然后,每次取出6(因为)个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。
如果最后剩下两个输入数据,在编码结果后加1“=”;如果最后剩下一个输入数据,编码结果后加2“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。
Base64索引表:


Value


Char


 


Value


Char


 


Value


Char


 


Value


Char


0


A


16


Q


32


g


48


w


1


B


17


R


33


h


49


x


2


C


18


S


34


i


50


y


3


D


19


T


35


j


51


z


4


E


20


U


36


k


52


0


5


F


21


V


37


l


53


1


6


G


22


W


38


m


54


2


7


H


23


X


39


n


55


3


8


I


24


Y


40


o


56


4


9


J


25


Z


41


p


57


5


10


K


26


a


42


q


58


6


11


L


27


b


43


r


59


7


12


M


28


c


44


s


60


8


13


N


29


d


45


t


61


9


14


O


30


e


46


u


62


+


15


P


31


f


47


v


63


/


 
二进制转成Base64编码
按照算法描述:
1、讲输入数据按3个字节组成一组3*8=24位的整数;
2、然后将其按24/6=4位一组分为4组;
3、每组6位算出取值,在base64索引表中查看对应的字符,即可;
4、如果还有模3剩余的1个字节数据,则补2个字节的0,将转换成的4字符的最后2个替换成”==”
5、如果还有模3剩余的2个字节数据,则补1个字节的0,将转换成的4字符的最后1个替换成”=”
其中1-3步容易理解和编写,第45步的实现方法可能有很多种,但是考虑到可读性,而且每次转换之多执行其中一步,可以使用如下中的硬编码:
 

_CODE_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def binbase64(data):
"""
Convert binary data to Base64 format string.
"""
base64str = ""
for i in range(len(data)/3):
datavalue = ((data[3*i] << 16) | (data[3*i+1] << 8) | data[3*i+2])
for j in range(4):
base64str += _CODE_CHAR[(datavalue >> 6*(3-j)) & 0x3F]
dataremain = len(data) % 3
if dataremain == 1:
datavalue = data[-1] << 16;
base64str += _CODE_CHAR[(datavalue >> 18) & 0x3F]
base64str += _CODE_CHAR[(datavalue >> 12) & 0x3F]
base64str += "=="
elif dataremain == 2:
datavalue = (data[-2] << 16) | (data[-1] << 8);
base64str += _CODE_CHAR[(datavalue >> 18) & 0x3F]
base64str += _CODE_CHAR[(datavalue >> 12) & 0x3F]
base64str += _CODE_CHAR[(datavalue >> 6) & 0x3F]
base64str += "="
return base64str
  
  Base64解码转成二进制
 
解码之前要对输入数据有效性进行必要的判断,如长度是否为4的整数倍,有没有非法字符等。解码步骤为:
1、取4个字符组成一组,判断每个字符在Base64索引表中的索引值;
2、将索引值转成6位二进制,并组4*6=24位的整数;
3、再将这个24位的整数分成24/8=3个字节;
4、如果末尾有2个"==",则只有1个有效字节
5、如果末尾有1个"=",在有2个有效字节
 

class Base64Error(Exception):
"""
Exception for Base64 error.
"""
pass
def base64bin(encodedstr):
"""
Convert Base64 format string to binary data.
"""
if len(encodedstr) % 4:
raise Base64Error("The length of input 'base64str' MUST be multiple of 4.")
rawbase64str = encodedstr.rstrip("=")
if (len(rawbase64str) % 4) == 1:
raise Base64Error("Too many '=' characters, MUST NOT be more than 2.")
for x in rawbase64str:
if x not in _CODE_CHAR:
raise Base64Error("Unexpected character %s.", x)
data=[]
for i in range(len(rawbase64str)/4):
datavalue = (_CODE_CHAR.find(rawbase64str[4*i]) << 18) \
| (_CODE_CHAR.find(rawbase64str[4*i+1]) << 12) \
| (_CODE_CHAR.find(rawbase64str[4*i+2]) << 6) \
| (_CODE_CHAR.find(rawbase64str[4*i+3]))
data.append((datavalue >> 16) & 0xFF)
data.append((datavalue >> 8) & 0xFF)
data.append((datavalue) & 0xFF)
strremain = len(rawbase64str) % 4
if strremain == 2:
datavalue = (_CODE_CHAR.find(rawbase64str[-2]) << 18) \
| (_CODE_CHAR.find(rawbase64str[-1]) << 12)
data.append((datavalue >> 16) & 0xFF)
elif strremain == 3:
datavalue = (_CODE_CHAR.find(rawbase64str[-3]) << 18) \
| (_CODE_CHAR.find(rawbase64str[-2]) << 12) \
| (_CODE_CHAR.find(rawbase64str[-1]) << 6)
data.append((datavalue >> 16) & 0xFF)
data.append((datavalue >> 8) & 0xFF)
return data
 
  字符串转换
 

def strbase64(astr):
"""
Convert a string to Base64 format string.
"""
return binbase64(map(ord, astr))
def base64str(encodedstr):
"""
Convert Base64 format string to a string.
"""
return "".join(map(chr,base64bin(encodedstr)))
 
  
文件转换
文件转换要用到这里介绍的filehleper。另外,RFC 822规定,Base64文本没行76个字符,可存76/4*3=57个字节。所以我们每次读入57个字节处理。
 

def binfiletobase64(inp, out):
"""
Convert binary file to Base64 format text file.
"""
blocksize = 76 / 4 * 3
def _binfiletobase64(fin, fout):
while True:
chunk = fin.read(blocksize)
if chunk:
fout.write(strbase64(chunk))
fout.write("\n")
else:
break
fileinoutpattern(inp, out, _binfiletobase64, inmode="rb", outmode="w")
def base64filetobin(inp, out):
"""
Convert Base64 format text file to binary file.
"""
def _base64filetobin(fin, fout):
for line in fin:
fout.write(base64str(line.rstrip()))
fileinoutpattern(inp, out, _base64filetobin, inmode="r", outmode="wb")
测试代码

def test():
"""
Self testing.
"""
rawstr = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."
encodedstr = binbase64(map(ord, rawstr))
for x in range(0, len(encodedstr), 76):
print encodedstr[x:x+76]
encodedstr = strbase64(rawstr)
for x in range(0, len(encodedstr), 76):
print encodedstr[x:x+76]
data = base64bin(encodedstr)
decodedstr =  "".join(map(chr,data))
print decodedstr
assert decodedstr == rawstr
decodedstr = base64str(encodedstr)
print decodedstr
assert decodedstr == rawstr
#base64str(encodedstr[:-1]);#Not multiple of 4
#base64str(encodedstr[:-3]+"==");#Too many '='
#base64str(encodedstr[:-2]+"()");#Invaild characters '(' and ')'
binfiletobase64(r"D:\2.zip", r"D:\2.txt")
base64filetobin(r"D:\2.txt", r"D:\2.1.zip")
print "OK"
源代码下载binbase64.zip

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-374567-1-1.html 上篇帖子: 使用python抓取网页(以人人网新鲜事和团购网信息为例) 下篇帖子: 用python编写递归爬取多重网址的网站信息
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表