“画蛇添足”的Python

标签: , , ,

Python,直译是蟒蛇的意思,和画蛇添足似乎有那么点联系。今天就遇到了一个Python“画蛇添足”的问题。傍晚的时候有人加我QQ,说是请教Python问题,于是就通过了。通过后才发现,原来他之前加过我,前段时间清理QQ,把一些很少说话的人删掉了,其中就有他。问题是这样描述的:

我遇到难题啦,百思不得其解,帮我看段代码好吗?a768.neu是加密过的文件,我要把它改回原来的样子。事实上它也变成原来的样子了,但是这个还原文件变大了好几百K,按道理来说应该是一样大小才对。在for循环里的就是改密过程了,好像比较笨的方法。之前有人帮我用VBS也做了一个像这样的改密代码,但好像解出来的是比原来的文件小了点。

然后给我传了一个qq.py脚本和a768.neu文件(点击此处下载):

f=open("a768.neu")
a=f.read().encode("hex")
f.close()
k=""
for i in range(len(a)):
    if a[i]=="1":
        k=k+"c"
    if a[i]=="2":
        k=k+"f"
    if a[i]=="3":
        k=k+"e"
    if a[i]=="4":
        k=k+"9"
    if a[i]=="5":
        k=k+"8"
    if a[i]=="6":
        k=k+"b"
    if a[i]=="7":
        k=k+"a"
    if a[i]=="8":
        k=k+"5"
    if a[i]=="9":
        k=k+"4"
    if a[i]=="0":
        k=k+"d"
    if a[i]=="a":
        k=k+"7"
    if a[i]=="b":
        k=k+"6"
    if a[i]=="c":
        k=k+"1"
    if a[i]=="d":
        k=k+"0"
    if a[i]=="e":
        k=k+"3"
    if a[i]=="f":
        k=k+"2"

f=open("aaabbb.bin","w")
qq=k.decode("hex")
wt=f.write(qq)
f.close()

乖乖,虽然我的原则是能用就行,但是这代码写得也太烂了点,算了,这不是重点。我很少用Python,系统上连Python都没有,下载个ActivePython-2.7.1.4,安装后运行了一下程序,得到的文件果然比原来的文件大。从算法上看,解密后的文件的大小应该是不变的,但是事实却摆在面前,我思索了一下,没有头绪。

我说过,我只看过一点Python,而且因为不知道用来做什么,几乎没实践过。问我Python的问题也许还不如到百度知道之类的垃圾问答网站上去问。不过既然有人问了,我还是会尽量去解决的,于是请教了一下Python用得比较多的ihipop。

他在哪里说了一堆完全不着边际的话以后,终于说了一句靠谱点的话:“Unix系统和 Windows系统的换行符是不一样的。解密后的文件比原来大多少?”其实解密以后的文件是纯文本,我也打开过,但是没有注意过大了多少。

于是对比了一下,a768.neu是1,439,278字节,而aaabbb.bin是1,465,157字节,多了25879字节,用EditPlus打开aaabbb.bin文件,正好25879行,这绝对不是偶然。Unix下的换行符是\n,而Windows下的换行符是\r\n,一定是Python“画蛇添足”,把\n替换成\r\n了,于是每行多出一个字节,25879行正好多出25879字节。ihipop把程序放到Linux服务器上运行了一下,解密后的文件大小和原来一样,仍然是1,465,157。

但是转念一想,像Python这么优秀的脚本,不可能背着我们偷偷地做“画蛇添足”的事情,一定是代码某个地方写错了。又仔细看了一遍代码,发现了可疑之处:

f=open("aaabbb.bin","w")

查了一下Python的帮助文档关于open函数的说明:

The most commonly-used values of mode are 'r' for reading, 'w' for writing (truncating the file if it already exists), and 'a' for appending (which on some Unix systems means that all writes append to the end of the file regardless of the current seek position). If mode is omitted, it defaults to 'r'. The default is to use text mode, which may convert '\n' characters to a platform-specific representation on writing and back on reading. Thus, when opening a binary file, you should append 'b' to the mode value to open the file in binary mode, which will improve portability.

重点是紫色部分:默认使用的是文本模式,在读写文件时,会把\n字符转化成与平台有关的字符。而上面的代码,恰恰使用了文本写模式w,如果是在Windows下运行,Python会自动把\n转化成\r\n。看来,并不是Python画蛇添足,而是写代码的人(当然,也包括我)不明真相。

其实我早该想到的,Python的open函数的内部是用C标准库函数fopen来实现的,fopen也分为文本模式和二进制模式。只可惜我一直以来用的都是二进制模式,直接把文件模式忽略掉了,就没考虑到这层。

解决的方法很简单,把文本模式w改成二进制模式wb就行了。至于别人帮他用VBS写的程序,显然是写错了(或者难道他把\n全部去掉了?)。用VBS来处理1M多的二进制文件,如果不经过优化,效率是非常低的。我试着用和上面的Python同样的算法写了一个VBS,双击后去洗了个澡回来还在运行,被我直接结束进程了。我很好奇那个人的VBS是怎么写的,把文件解密出来用了多少时间。

最后,附上我修改后的代码,虽然我的Python水平并不是鬼使神差,但是比起上面的代码,要简洁得多:

f = open("a768.neu", "rb")
a = f.read().encode("hex")
f.close()

table = ["D", "C", "F", "E", "9", "8", "B", "A", "5", "4", "7", "6", "1", "0", "3", "2"]
k = ""
for i in a:
	k = k + table[int(i, 16)]

f = open("demon.bin", "wb")
f.write(k.decode("hex"))
f.close()
赞赏

微信赞赏支付宝赞赏

随机文章:

  1. 快捷方式都以IE打开的解决方法
  2. MSDN 6.0 简体中文完全版下载
  3. MySQL的Unicode支持
  4. JavaScript中的闭包(closures)
  5. VBS脚本设置虚拟内存大小和位置

9 条评论 发表在““画蛇添足”的Python”上

  1. yexingzhe说道:

    阅了~我也要掌握点py

  2. Firefly说道:

    记得我前一段时间也才了解到Windows、Linux和Mac下的换行和回车有不同之处,不过总算今天看到例子了。
    “双击后去洗了个澡回来还在运行,被我直接结束进程了”,此处应有掌声!`(*∩_∩*)′

  3. ihipop说道:

    我受伤了 心里受伤了

  4. Kaisir说道:

    哈哈 py 这个语言是很神奇 语法严格的想死……

  5. Kaisir说道:

    不过,这个neu是什么文件?什么加密算法?

  6. huakeha说道:

    谢谢啦!正在消化中!

  7. Tales说道:

    这篇文章的重点在于和谁洗澡……
    是我的话我肯定是开头写f.open和g.open,然后最后写两个的close
    哪种更好?还是说都一样?

  8. flyshare说道:

    d = {‘1’: ‘c’, ‘2’: ‘f’, ‘3’: ‘e’, ‘4’: ‘9’, ‘5’: ‘8’, ‘6’: ‘b’, ‘7’: ‘a’, ‘8’: ‘5’,
    ‘9’: ‘4’, ‘0’: ‘d’, ‘a’: ‘b’, ‘b’: ‘6’, ‘c’: ‘1’, ‘d’: ‘0’, ‘e’: ‘3’, ‘f’: ‘2’}

    with open(‘A768.neu’, ‘rb’) as f:
    img = f.read().encode(‘hex’)

    buf = map(d.get, img)
    with open(‘decode.bin’, ‘wb’) as f:
    f.write(”.join(buf).decode(‘hex’))

留下回复