北京今夜有星星
昨天一出门,我啪地坐了个屁墩,结结实实地。我坐在那里,半天没起来。头几秒是搞清楚状况,接下来几秒用来确定腰间盘等部分尚可用,最后几秒抬起撑在地上的手掌,看看伤的情况。一概没大事,后背有些拉伤,尾椎骨有点疼。大清早,来来回回有几个行人扭头看我。我做出痛苦状,以表示自己不是傻气发作坐在那里。
后面又出来一位,我大喝一声"小心脚下,特别滑!"他没摔到。
我以前从来没见过这种路面,有冰,但是特别薄,冰是透明的,不注意反光就完全看不到。今天听北京人民说,这叫做"地穿甲"。不是穿山甲,是地面穿了一层甲。头一天晚上下了"冻雨",据我看是冷冻的雾,半夜时融化成水,清早里都结成冰铺在地面上了。东北的天更冷,一般把冰冻出裂纹来,所以不会出现这种东西。在东北,雪或者冰即使偶尔融化,也不是水气这么少的时候。我见过一次三九四九不出手的时候,下了场大雨。不过,第二三天结的冰很厚,全然不是北京这种让人冷不防的。
说实话,写到这里的时候,我想起了北京人民喜欢说的一句话,跟你讨论半天,尤其是否定你的时候,末了来一句,"好吧"。语气你自己想像,但是绝不是和你商量讨论呢。
好在冷空气带来了晴天。天天没太阳,天天乌突突。外面空气次得不行,学员们偏偏习惯开着窗户透气,这空气透还不如不透呐。终于晴天。早晨有蓝天,上午有太阳,下午阴天,晚上有星星。
附照片一张,以资证明,中间那几颗亮点不是噪音,是星星。
最近正读色诺芬《长征记》。这位大哥真是牛人也,跟波斯王子居鲁士去打国王,这边打得正欢,居鲁士挂了;有位带头大哥站出来带领大家回家,没多久带头大哥挂了。半夜大家都躺帐蓬里等死等天亮,色诺芬站出来说服大家要打回老家去。难得的是,色诺芬还是谦谦君子,正经是个好脾气的,屡次被大家背叛抛弃,仍然救助士兵如故。军事战术也好,少有的退师作战没有给养,还能占到些便宜。他的《长征记》激励亚历山大,原来波斯也没啥牛的,这才有远征亚洲。
可惜色诺芬这样的好人,后来也死掉了。
--------------------
博客会手工同步到以下地址:
北京北京
1月底2月初,我在北京停留一周。西北四环,我不知道这里算是城郊,还是几座村镇的中间地带。
灰蒙蒙的天空,正午的太阳终于显露出来,月亮一样黯淡。眼前低矮的建筑,狭窄的胡同,远处高楼林立,隐在雾霾之中。豪华轿车上厚厚一层灰尘,它们飞速穿过西四环宽阔的马路,溶入到闪耀的车灯的洪流中。
我看到穿着深色掐腰西服的青年男女,里面是雪白的衫衣,他们涂脂抹粉,在终日不暗的人工光源照射下活力四射,然后挤在百货公司楼顶的食铺里吃得大汗淋漓。他们操着不太纯正的北京方言,谈论着与家乡遥远不可及的话题。
他们的后代会成为操着纯正京腔的北京人民。我不禁想,当他们的后代长大,那时的北京是个什么样的城市。过街天桥上很多大红的标语在雾气里隐约可见,我记得"首善之区"这四个字,取代了上次我看时看到的"包容"等北京精神。上一次我见到"首善之区",似乎是在鲁迅先生作品的脚注里。这么眼熟。
收音机是吉克隽逸祝福和号召的声音,还有李代沫的新歌。我翻出梁博的《北京北京》,他在选秀以后渐渐淡出了人们的视野,似乎没有新歌没有宣传。他说过,他热爱音乐,我现在更加相信了。
我还看到汪峰和几个别的明星穿着登山服的大幅广告,在城市中心,在地铁的灯箱里。他们似乎都向往远山,向往自由,向往天空。
你的行为告诉我们,你所热爱的到底是什么。他们,最终选择了北京,而不是他们所热爱的故园、旷野和音乐。
更多照片 [http://www.douban.com/photos/album/85517092/?start=0],其中有两张是长春。
--------------------
博客会手工同步到以下地址:
《C程序设计语言》句读 20130123
《C程序设计语言》句读 20130123
在这里[http://www.tudou.com/programs/view/XKF8AOADykU/]。
这次结束了第1.2节。华氏度转摄氏度的程序已经由整型版本改成了浮点数版本。这一次的主要内容是while的循环体,还有数据类型及实加于其上的运算间的关系。
--------------------
博客会手工同步到以下地址:
[http://giftdotyoung.blogspot.com]
[http://blog.csdn.net/younggift]
--
Sincerely,
YANG Guifu
School of Computer Science and Information Technology
Northeast Normal University
Changchun, P.R.China
----
杨贵福
无不大工。
《C程序设计语言》句读 20130120
《C程序设计语言》句读 20130120
在这里[http://www.tudou.com/programs/view/F80XyfJFBYE/]。
这次开始第1章,小程序示范。Hello world结束了,正讲到华氏度转摄氏度的循环。
--------------------
博客会手工同步到以下地址:
《C程序设计语言》句读 20130117
《C程序设计语言》句读 20130117在这里[http://www.tudou.com/programs/view/IP0uddL3wX8/]。这次句读完了绪论,第1章刚刚开始。我按现在的进度估算了一下总共需要的时间。全书一共190页,如果每次2页,我们需要95次,如果每周一次,需要95周,需要1.76923076923年。不到2年的时间。我又想起当年考研还是考博时的犹豫,犹豫所需要的时间,还有学完要花费又几年的时间。当时一个贴子让我明白了一点。贴子说,一个家伙犹豫要不要考研,心想,等我毕业需要三四年,那时我都快40了。我还要不要考呢?他的朋友说,你以为你不考,过三四就不四十了么?句读C语言需要两年的时间。我自问自己,你真以为如果不句读C语言,这两年就能做更有意义的事情啦?我们有时并不是有更重要的事情要去做,不过是对现状的绝望。
今天有领导训示大家,关于科研考核什么烂糟的。不是科研考核本身烂糟的,我是说我的科研成果烂糟的。有位同事说,"计算机学科这么弱,跟化学生物物理同一个标准不合适。"我不太以为然,自己不行么,要么争气,要么认命,也没啥可争的。包师弟有云,"眉毛上的汗水,眉毛下的泪水,你总得选一个。"反正你如果有目标,总归得工作或者哭。不过我不敢跟我的学生们说,怕他们认为我是在励志。因为我总记得我们最终还有一条路可选,就是放弃目标。但这话不能跟同学们说,他们该投诉我了。同事提到的学科差异,领导开玩笑地说,"那就得怪你选错学科了。"大家笑。我没配合笑一下,而且非常激动。所以当另一位领域问俺们,不是,问我有啥想法时,我就表达了一下。我们学科弱不错,全世界的计算机都比化学生物物理弱,也不错。但是我们热爱这个学科,你不能说我们选错了学科。就算你把我们拆了,全分到各个系看机房,我们还是热爱这个学科。上述,我表达得有点语无伦次,现场效果也就是如此。其实我想说的是,我没有别的选择,我只喜欢计算机。所以,我也没有什么别的可以做的。人人网还是哪,以前有过微博类调查,说如果没有你学习从事的这个专业,你想做啥去。如果那样,我想去死。没有别的选择的时候,人生就完全不同了。至少,你不会因为选择痛苦--因为你别无选择。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
读书怎么才能更快
读书怎么才能更快沙发上堆了不少书,这些都是计划要看完的。有的要精读,有的要粗读。精读和精读消耗的时间相差巨大。大抵上,读书想要更快,速度就在精读和粗读的速度差上了。当然,排除一种方法,就是你一顿瞎翻,啥也没记住。李笑来先生曾经说过,读书提速的方法,根本没有秘诀。无外乎多读,多读你的速度就快了。你可能问了,为啥啊。有人可能还听说过一种叫"快速阅读"的技术。练习以后,能一行一行地往下看,不是一个字一个字的看。大致上,跟竖着看书差不多。我小学的时候学过,貌似还有点用。英语阅读的时候,我能用别人一半的时间完成阅读和答题--当然准确率并不怎么出色。不过,即使我降速到原来的一半,准确率也就还是那样。这样看来,"快速阅读"似乎还有点用?这跟李笑来先生提到的没有秘诀是否矛盾呢?其实,不矛盾,都是一回事。一者,长时间地阅读,会自然地形成很多技巧,这些技术就跟走路多了的人会走路一样:把文字按行或按词组划分,不要每个字都读,跳着读,不要在心里出声,啥的。要想阅读超过人类的正常语速,还是挺容易的,只要读足够的量。所以,一般没有特殊训练,也容易达到。不过,当我们读教科书、经典著作,或者我们称为晦涩难懂的那些书的时候,问题就来了。这个时候快速阅读完全起到了相反的作用。比如第一次读《C程序设计语言》,比如读《纯粹理性批判》,比如读你明天要考试的那科教材。一目十行,合上就忘,甚至当时也不知道作者在说些啥。所以,计算机领域有一种说法,他们希望发明一种"慢速阅读"方法,从而能字斟句酌地一点点扣。这种时候最好的读书法是 不仅"读",而且"做"。正如CSAPP中说的,学习系统的最好方法,就是 "do
system"。当你沉浸其中,不看书实现一遍那些代码的时候,你就真正掌握了。有的似乎把这叫做在"内化"。扮演老师,给别人讲明白;找个实例按书里的路子剖析一遍……总之,经历过的事情,会让你刻骨不忘。这就是为什么讲起近三十几年的历史,三十几岁的人往往连书都不用翻,因为他们身在其中。当然,"do system"的方法,是个慢方法,而不是个快方法。不过,如果吃了东西都不消化,还吃它干什么。所以,"do
system"也是大量阅读中的好方法。更好的方法,是自己写一本。大量阅读,会自然形成阅读技巧,因此,会读得快。但大量阅读的作用,不止于此。其二,大量阅读会形成知识结构。这样,不仅技术使你读得快,知识结构还会使你越读越快。我面对那么书,也常常挠头,叹"吾生也有涯而知也无涯",悲夫。不过,到真正读的时候发现,有的书读起来比想像地快得多。比如我用一个晚上读完了今何在先生的《我的征途是星辰大海》,用大半个晚上读了半本二月河先生的《九王夺嫡》。这种速度和某些速读牛人比起来并不算什么,不过和我其他的记录相比就令我惊叹了。我读SICP的时候,有过2个小时1页的时候,读康德的时候,有好几天断断续续没翻过去一页的时候。和这些比起来,一晚上半本一本的速度就很快了。为什么会有这种差别呢?一个原因是,这些书的信息含量是不同的。信息论告诉我们:信息,是对无序的度量,只有当可能性未知时,即事件你还不知道结果的时候,告诉你的,才是信息。你明知道的事情,我再说一遍,对你而言是零信息。那种对话一般表达情感,或者是仪式,比如那句古老的"你吃了吗"或者"how
are you"。其实说话人对你吃了没有或者好不好一点也不感兴趣。小说和电影,如果只是为了欣赏,而非研究学习,那读起来就可以酣畅淋漓。按Johan Lilius教授对 the Big
Bang的评价,把脑子拿走一些看,效果会更好。按《破产姐妹》里胖姑娘的说法,对着电影大喊大叫,那正是享受电影。这样的时间,过得很快,其实也真的不多。一场电影1.5小时,可能康德还没有读完半页。另一种读起来快的书,就是里面的知识全是你知道的。我们翻金庸原版武侠的时候,感觉大概就是这样。谁什么时候要死了,什么时候要难过,后面还有啥阴谋,咱们全知道。只是为了再感动一次。可以几秒钟就翻过一页,如果不细品文字的话。还有精通一种语言的人,再学习其他的语言,看教材的时候,速度也非常快。因为他的头脑中,不管什么语言,都应该有变量声明、类型、结构体、数组、对象、判断、循环、函数、库。一般都这样,内容不变,只是语法上有差别。除非,你遇到了颠覆你人生观世界观价值观的东西。比如,LISP有那么一大堆括号不让人头疼,很多初学者的第一个问题是,这家伙没有循环怎么迭代,然后可能又遇到个问题,函数怎么可以没有名字,可能还会有人疑惑变量怎么可能没有类型。再比如,PYTHON初学者可能对结束没有";"还没有多大意见,缩进是语法的一部分,很多人好几年适应不过来。还有,当你打开罗素康德,看到他们所讨论的有的似乎你疑惑者,有的你根本不知道他们在说什么。他咔咔一顿推导,最后得出一个你万万不能支持的结论,突破了小资产阶级所谓"底线"。这可不行,还得掉头看他怎么推理的,或者扔掉再踩上一脚,评"什么破玩艺",或者"我可整不了"。所有这些,lisp,python,康德罗素,他们让我们不舒服,让我们阅读的速度大大降低,原因在于--他们正拓展我们的知识结构。探索新宇宙,开疆拓土,历来如此。想舒服,想快速,就停留在我们原有的知识结构上。拿起本小学数学,或者初中二元一次方程,那感觉,是不是很自信。我以前装机试软件的时候,曾经装过一个软件,考10以内加减法。我做完题,机器评论"你看是个天才"。但是我并没有什么满足感,只是觉得滑稽而已。大部分小学生看你现在要考试的教材,速度肯定比你慢上百倍。他的阅读速度,甚至认字和组词的能力,都阻碍他的理解。更重要的,你已经具备了这本教材的知识结构。知识结构的完备,大大减少了我们阅读时的信息量。读我们熟悉的东西,不过是增加细枝末节的了解,而框架的建立,而是伤筋动骨,痛苦而漫长。这也是为什么我们人类那么痴迷于"形而上",因为我们期待建立了它以后,剩下的可以不用想就推出来了。所以,大量阅读建立的知识结构支持我们更快的阅读,因为它大大减少了书本中我们要接受的 (未知的) 信息数量,那些都是我们已经知道的了。而且,随着你阅读数量的增加,知识结构的完善,你的阅读会越来越快。因为,你的知识结构越完善,在下一本书里,你未知的就越少。有人可能提到"知道的越多,未知的越多",那是针对知识总量而言的,而不是指特定的某一本。特定的一本书,你知道的越多,读起来铁定越快。除非,你是在研究,而别人只是在浏览。再回到我沙发上的那些书,精读和粗读。凡是新知识结构,都只能精读,这是没有别的办法的事情;娱乐的、补允细节知识的、学习别人表述方法的,那些读起来就快得多了。读书怎么才能更快?读得多了,就快了。你可能认为这是个悖论,因为你想知道读书快速的方法,就是为了多读书。不是的,你不是想多读书,而是想利用更少的时间读书。这个问题容易答多了:只有现在花时间多读书,以后才能少花时间。再说了,人生苦短,可也够长。你没用在读书上的那些时间打算干什么,打麻将么?--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
--
Sincerely,
YANG Guifu
School of Computer Science and Information Technology
Northeast Normal University
Changchun, P.R.China
----
杨贵福
无不大工。
精读经典,重新开始:《C程序设计语言》句读
精读经典,重新开始:《C程序设计语言》句读康德如此闻名,没有人敢慎重地说他写得都是些什么玩意,根本看不懂。但是,一直以来,很多人都提到,康德的著作太难读了,这抱怨还是针对汉译的。《纯粹理性批判》中文版,看着跟德文似的。所幸,邓晓芒先生著有《<纯粹理性批判>句读》,逐句翻译和扩展。这让我满怀希望,也许经过努力,总有一天能够明白。类似受到推崇和抱怨的,还有《C程序设计语言》一书,C和UNIX操作系统的发明人 K&R
两位先生的著作,是最优秀的C语言教科书。我在本科的时候幸运地从学校图书馆借到过这本,薄薄的小册子,讲解清楚明白。虽然我后来又读了很多书,它仍是对我影响最大的和最优秀的书之一。其他的,还有《牛虻》和《计算机解释的构造和解释》。牛的书,重构我们的人生观世界观价值观,或者知识结构,给我们新的生命。我对我的学生,我的学生也对我说过,要精读经典,重读经典,一遍又一遍。每一遍可能都有不同的体悟。贯彻这一原则,很久以来我一直想再次精读此书,并且希望我通读全书的过程能有益于你。所以,我开始录音这个过程,发布在网上。在这个录音中,有我的中文口音、我不认识的单词去查的过程,可能以后,还有你纠正了我的错误,我在以后的某次承认错误免得误导别人和对你的感谢。在这个录音中,还有我通读这本书的每一句,然后像英语精读课那样,划分句子成分,解释一些单词,从英语的语意,到计算机领域中它特殊的含义。还有我的各种猜测。这些过程,你都熟悉。你需要一本书,机械工业出版社 《C程序设计语言》英文版 第2版,作者 Brian W. Kernighan, Dennis M.
Ritchie,2009年3月第1版。其他的版本可能也行,内容也许略有差异。也许,你还需要一支笔,用于标注生词、句子的语法结构,一些知识点。你还需要一些时间,每一次大约45分钟。我会不定期更新,上传,然后在这里通报一下。我需要你的意见,如果你方便和乐意。受我的水平所限,难以保证正确和深入,愿与同样的初学者一起进步;也请大牛们指正,谢谢你帮助我进步。康德在《实践理性批判》中说:"有两样东西,愈是经常和持久地思考它们,对它们日久弥新和不断增长之魅力以及崇敬之情就愈加充实着心灵:我头顶的星空,和我心中的道德律令。"我想,他说的是,道德律令之于人类,就像星空一样真实地存在。可以触摸和感受,不可避免地影响我们,无法逃避。我们来自于它,归结于它。C程序设计语言,也是的。录音在这里,[http://www.tudou.com/programs/view/7uHPX99xDaA/]。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
用邮件分割和传送大文件,python实现 III
用邮件分割和传送大文件,python实现 III4. 接收端baoyu4.1 导言和import这部分,是从zhumao.py中抄过来的。1 #! /usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # baoyu, 邮件接收者
5 __usage__ = "usage: %baoyu.py [--help]"
6 __version__ = "baoyu by Young 2012-12-21"
7
8 from optparse import OptionParser
9 import base64
10 import time
11 import sys
12 import poplib
13 import time
14 from email.Parser import Parser
15 from email.header import decode_header
164.2 helper函数们这里是一些在后面的业务逻辑实现中要调用的一些函数。它们在此声明和定义,定义的方式一般应依据动机、目的,而不是根据实现手段。也就是说,使用的词汇应该是分析阶段的词汇。函数被从"后面的业务逻辑"中抽取到这里,可能因为被调用很多次,也可能只调用一次,但是在业务上具有较为鲜明的特征。如果调用很多次,抽取出来的原因之一就是重用,这样可以避免后续维护的时候一旦有修改需求,这个功能相关的很多地方都要修改;如果只调用一次,但是业务特征明显,就是为了信息隐藏,以后或别人读代码的时候要容易一些。根据场合和组织方式的差异,这些函数有不同的称呼。在C++/java中,私有函数基本上实现了这样的功能;在flex/bison及我一时没想起来的很多领域中,它们被称为helper函数。17 ######
18 # helpers
19 ######
20 def getheader(header_text, default="ascii"):
21 """Decode the specified header"""
22 try:
23 headers = decode_header(header_text)
24 header_sections = [unicode(text, charset or default)
25 for text, charset in headers]
26 return u"".join(header_sections)
27 except:
28 return u"".join("invalidated encode")
29上面的代码是从某位貌似日本人的站点上抄来的,它的名字其实不应该叫做getheader,而是"根据charset解码"邮件头或正文。30 def get_msg(which):
31 return "n".join(server.top(which, 1)[1])这是根据 which指定的邮件id号,从邮件服务器上取得对应的邮件,但是不删除。server.top()。详见手册[http://docs.python.org/2/library/poplib.html],"POP3.top(which,
howmuch)"。33 def get_from(msg):
34 email = parser.parsestr(msg)
35 return email.get("From")上述的 pserser 就是 第14行 "from email.Parser import Parser"
中的Parser的实例,在下面的第82行。手册[http://docs.python.org/2/library/email.parser.html]。这个parser是专门用来从邮件中析出邮件头部等各个部分的。第35行,解析出From部分,也就是邮件发送者地址。baoyu.py根据这个来判断某封邮件符合"zhumao-baoyu"协议的发送者部分。这个粗糙的协议包括:发送者、邮件主题、第几封邮件、共几封。其中,发送者和邮件主题作为下载和删除邮件的过滤条件。37 def get_body(which):
38 msg = "n".join(server.retr(which)[1])
39 email = parser.parsestr(msg)
40 return email.get("BODY_START")与第33行开始的函数类似,get_body用于取得which指定的id对应的邮件的body。不同的是,get_body把这封邮件标记为已读。此外,上文提到,我们为了解析方便,在body的开头标记了"BODY_START:",所以此处,body可以视为"BODY_START"部分的值。42 def get_subject(msg):
43 return getheader(parser.parsestr(msg).get("Subject"))还是与第33行开始的函数类似,取主题部分。45 # e.g. [base64-2] 1/2
46 def get_cur_num(subject, subject_prefix):
47 start = subject.find(opt.subject_prefix)+len(opt.subject_prefix)
48 slash = subject.find('/', start)
49 return int(subject[start:slash])51 def get_all_num(subject, subject_prefix):
52 start = subject.find(opt.subject_prefix)+len(opt.subject_prefix)
53 slash = subject.find('/', start)
54 return int(subject[slash+1:])以上两个函数,是从邮件头里取得这是第几个包、一共几个包这两个数据,使用的方法是字符串处理,以"/"分割类似"[base64-2] 1/2"的邮件头部。4.3 命令行解析与发送端zhumao.py的命令行解析类似,解释从略。57 #--------------------------------------------------------------------
58 # 命令行解析
59 p = OptionParser(usage=__usage__, version=__version__, description=__doc__)
60 p.add_option("-F", "--file", dest="filename",
61 help="file need to be saved", metavar="FILE",
62 default="test.out")
63 p.add_option("-P", "--pop", dest="pop",
64 help="pop3 server", metavar="POP3_SERVER",
65 default="pop3.nenu.edu.cn")
66 p.add_option("-u", "--user", dest="user",
67 help="user name", metavar="USER")
68 p.add_option("-p", "--password", dest="password",
69 help="password", metavar="PASSWORD")
70 p.add_option("-f", "--from", dest="fromaddr",
71 help="from whom to be filtered", metavar="FROM",
72 default='[email protected]' )
73 p.add_option("-L", "--subject", dest="subject_prefix",
74 help="the prefix of mail subject as filter",
metavar="subject_prefix",
75 default='[zhumao_baoyu_mail]')
76
77 (opt, args) = p.parse_args()
784.4 准备连接邮件服务器82 parser = Parser()
83 server = poplib.POP3(opt.pop)
84 server.user(opt.user)
85 server.pass_(opt.password)
86 server.set_debuglevel(0)
87 sleep = 0.1
88 count = server.stat()[0]
89 d = dict()使用pop3接收,各种参数设置。第88行,取得stat命令时的邮件数量,即未读邮件数量。第89行,初始化一个字典 (映射)。后面准备把第1封邮件放到"1"的值里面,第2封邮件放到"2"的值里面,依此类推。这样,在拼邮件的时候,可以按key排序。4.5 接收邮件检查邮件,根据邮件头过滤,下载并删除符合要求的邮件,显示接收百分比。从第90行到第107行,是一个循环,用于遍历所有邮件,并在第103行当查找到所有符合要求的邮件 (数量达到要求)以后跳出循环。90 for i in xrange(1, count, 1):
91 current = get_msg(i)调用helper函数 get_msg,取得id为i的邮件 (的邮件头和body第一行) 。92 if (get_from(current).find(opt.fromaddr) != -1 and
93 get_subject(current).find(opt.subject_prefix) != -1):
94 b = get_body(i)如果邮件的发送者符合要求 (比如 [email protected]) ,并且主题的prefix也符合要求 (比如 [base64-2]),取整封邮件。如果不过滤直接在遍历的时候取整封邮件,因为邮件数量众多,带附件的邮件又很大,性能会比较低。而仅遍历邮件头,对网络带宽就没有那么高的要求了。95 print '+-------------------------'
96 print '|' + str(i)+' '+ get_subject(current)
97 # print '|' + b
98 print '+-------------------------'显示进度,避免用户着急。99 current_seq = get_cur_num(get_subject(current), opt.subject_prefix)
100 all_number = get_all_num(get_subject(current),
opt.subject_prefix)调用helper函数,取得当前是这一文件的第几包邮件 和 一共几包邮件。一共几句邮件,数值在遍历中一直不会变,但是重复计算了很多次。101 print (str(current_seq) +'/'+ str(all_number))再显示进度,第几封,共几封。102 d [current_seq] = b把第N封邮件放到字典键N的位置。参见前面提到的第89行,这里是向字典中插入数据。103 if len(d) >= all_number :
104 break
106 else:
107 print 'filtered out: '+str(i)+'/'+str(count)+'
'+get_subject(current)如果把这个文件对应的所有邮件都已下载完毕,跳出循环;否则的话,也告诉用户一声,这封邮件不符合条件,不然出现大量不符合条件的邮件时,用户看到的是程序假死。109 server.quit()收完邮件,关闭连接,保持优雅。4.6 合并文件111 # 合并文件
112 s=""
113 for k in xrange(1, all_number+1, 1):
114 s += d[k]
115接key的顺序遍历字典d,把对应的值拼接在一起。这个对应的值来自第102行的插入,此处是取出数据。字典d综上所述,在第89行初始化,在第102行插入数据,在第114行读取使用。如果不用字典,而使用一个链表,以下标代替key,也可以。4.7 解码文件我们拼接出来的文件是base64编码的,所以需要解码,然后写出。116 # 解码文件
117 s = base64.standard_b64decode(s)
118
119 file = open (opt.filename, "w")
120 file.write(s)
5. 回顾数据流发送端的数据流为: 文件binary -> 读入文件 -> base64编码 -> cut -> smtp.接收端的数据流为:pop3 -> merge -> base64解码 -> 写出文件 -> 文件binary。如果思想的传递,也能无误地这样传输,该有多好。6. 进一步的工作还有很多进一步的工作可以做,让这个协议及应用程序更好一些。比如,加错误检校,指定重传错误的包而不是全部重传,由baoyu访问zhumao的共享目录并指定下载某个文件,不使用SMTP/POP3而是通过论坛的贴子传递信息。还可以在传送前加压缩 (不过对于视频和音频,没啥意义)。还可以用这种隧道做成反向代理……未来有无数种可能。可能这正是人生的迷人之处,如果今天就能看到明天及所有以后的日子,那还有什么希望可言。完整代码在这里 [http://my.csdn.net/my/code/detail/33574] 和
[http://my.csdn.net/my/code/detail/33573].--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
用邮件分割和传送大文件,python实现 II
用邮件分割和传送大文件,python实现 II3. 软件的使用过程下面这段,是软件写完以后运行的效果,不过,在软件开始写以前,它的样子就已经在我的心中。用个去年还是前年流行然后就消声匿迹的词来形容,软件在写第一行代码以前,就应该有个"愿景"。
以下,以发送191字节的 test.in
为例,分成3个包,每包100字节。从[email protected]发出,发给[email protected]。每包100字节是参数的默认值指定的。3.1. 发送方zhumao~/running/zhumao-baoyu-mail $ python zhumao.py -f [email protected] -t
[email protected] -L "[test-in]" -p "mypass***" -F test.inTo:[email protected] From: [email protected] Subject:[test-in] 1/3sent.To:[email protected] From: [email protected] Subject:[test-in] 2/3sent.To:[email protected] From: [email protected] Subject:[test-in] 3/3sent.3.2 接收方baoyu~/running/zhumao-baoyu-mail $ python baoyu.py -u [email protected] -p
"mypass***" -L "[test-in]" -f [email protected] -F test.out
+------------------------- |1 [test-in] 3/3 +-------------------------
3/3 +------------------------- |2 [test-in] 2/3
+------------------------- 2/3 +------------------------- |3 [test-in]
1/3 +------------------------- 1/3以上接收过程可以看到,一共3包,第3包的接收早于第2包,早于第1包。用diff对比发送和接收到的文件,一致。~/running/zhumao-baoyu-mail $ diff test.in test.out
~/running/zhumao-baoyu-mail $
3.3. 手册,帮助$ python zhumao.py --help Usage: %zhumao.py [--help]Options: --version show program's version number and exit -h, --help
show this help message and exit -F FILE, --file=FILE file need to be
sent -S SMTP_SERVER, --smtp=SMTP_SERVER smtp server -f FROM,
--from=FROM mail sender -p PASSWORD, --password=PASSWORD password -t
TO, --to=TO mail receiver -s SIZE, --size=SIZE size of each mail -L
subject_prefix, --subject=subject_prefix the prefix of mail subject$ python baoyu.py --help Usage: %baoyu.py [--help]Options: --version show program's version number and exit -h, --help
show this help message and exit -F FILE, --file=FILE file need to be
saved -P POP3_SERVER, --pop=POP3_SERVER pop3 server -u USER,
--user=USER user name -p PASSWORD, --password=PASSWORD password -f
FROM, --from=FROM from whom to be filtered -L subject_prefix,
--subject=subject_prefix the prefix of mail subject as filter4. 发送方zhumao以下是发送方zhumao.py的代码及讨论。希望能为像我一样的初学者带来启发的同时,渴望熟悉python什么的大牛们指导和批评我代码的各种错误,一方面我求进步,另一方面也免得我误导别人。谢谢啦。这两天又访问不了github了,所以暂时没传上去。各位将就着看吧。不连续的行号,是空行,我解释的时候略过了。4.1 基本相当于导言1 #! /usr/bin/python 2 # -*- coding: utf-8 -*- 3 4 # zhumao,邮件发送者第1行,注释,指定脚本解释器。这和shell程序设计是一个路子。第2行,注释,文件编码。祖国尚未统一世界,看来各种编码的乱像还会继续相当长时间。5 __usage__ = "usage: %zhumao.py [--help]" 6 __version__ = "zhumao by
Young 2012-12-21"我照抄的,看效果是显示使用方法。这个实现有意思,方便程序员与用户沟通啊。增加一点方便,估计就多几个百分比的程序员实现这一功能。8 from optparse import OptionParser 9 import smtplib 10 import base64
11 import time 12 import sys我猜就是 C里的include,猜的。还有名字空间、模块这样的作用。from的作用,似乎是使得模块中的符号名在当前作用域可见。这些模块是后面的代码要用到的。4.2 命令行解析这里使用了8 from optparse import OptionParser中指定的模块,第15行中的p是个OptionParser实例。在第16行以后,调用实例的方法
p.add_option。这些参数,基本可以根据出现的顺序、内容,与上述"愿景"对比,猜出来含义。不赘述。14 # 命令行解析15 p = OptionParser(usage=__usage__, version=__version__,
description=__doc__) 16 p.add_option("-F", "--file", dest="filename",
17 help="file need to be sent", metavar="FILE", default="test.in") 18
p.add_option("-S", "--smtp", dest="smtp", 19 help="smtp server",
metavar="SMTP_SERVER", default="smtp.nenu.edu.cn") 20 # help="smtp
server", metavar="SMTP_SERVER", default="smtp.gmail.com") 21
p.add_option("-f", "--from", dest="fromaddr", 22 help="mail sender",
metavar="FROM") 23 p.add_option("-p", "--password", dest="password",
24 help="password", metavar="PASSWORD") 25 p.add_option("-t", "--to",
dest="to", 26 help="mail receiver", metavar="TO") 27
p.add_option("-s", "--size", dest="size", 28 help="size of each mail",
metavar="SIZE", default=100) 29 p.add_option("-L", "--subject",
dest="subject_prefix", 30 help="the prefix of mail subject",
metavar="subject_prefix", default='[zhumao_baoyu_mail]') 31 32 (opt,
args) = p.parse_args()到这里为止,命令行参数 (及其默认值)就已经成为p的成员了。后面这样引用,比如: opt.smtp。第32行,这个返回值对C程序员来说,看起来有点奇特。手册[http://docs.python.org/2/library/optparse.html]说"parse_args() returns two values:options, an object containing values for all of your options—e.g. if
--file takes a single string argument, then options.file will be the
filename supplied by the user, or None if the user did not supply that
option args, the list of positional arguments leftover after parsing
options"4.3 输入文件34 # 输入文件35 file = open (opt.filename, "r") 36 s = file.read()第35行,opt.filename是从命令行中解析出来的,在我们的"愿景"中,就是test.in。open,
read,这样的写法,容易望文生义,而且似乎也对,不赘述。执行完这段以后,文件的内容全在s中了。4.4 编码文件38 # 编码文件39 s = base64.standard_b64encode(s) 40 41 ## sys.stdout.write(s)第39行,使用了 base64编码 字符串s,编码的结果再赋值给s。第41行是我写程序的时候用来输出测试的。4.5 准备发送,登录43 # 准备发送,登录44 sleep = 1 45 to = opt.to 46 user = opt.fromaddr 47 pwd
= opt.password 48 smtp = opt.smtp第44行,准备每发送一包睡一秒。根据你用的SMTP服务器对你的坏人判断有多严格,你可以调整sleep的值。从第45行至第48行,从命令行解析的结果中得到 发给谁、发送者、SMTP发送者的口令、SMTP服务器地址。49 smtpserver = smtplib.SMTP(smtp) 50 # smtpserver =
smtplib.SMTP(smtp, 587) # for gmail 51 smtpserver.ehlo() 52
smtpserver.starttls() 53 smtpserver.ehlo 54 smtpserver.login(user,
pwd)第49行使用smtplib,构造出smtpserver实例。如果用的是gmail,端口需要指定为587。从第51行到第54行,根据你选的smtp服务器的要求决定对它说些啥。我的smtp服务器要求先
扩展的hello,然后tls架密,然后再问候一次,然后登录。如果不知道应该说些啥,可以用thunderbird登录一次,用sniffer看一下正确的步骤。4.6 拆分-标记-发送麻烦的地方到了。4.6.1 拆成56 # 折分文件57 end = len(s) 58 for i in xrange(0, end, opt.size): 59 if
i+opt.size < end : 60 current = s[i:i+opt.size] 61 else: 62 current =
s[i:]python的for循环语法,我老是忘。希望这回能记住。"for 变量 in 待遍历的东西 : "。这里,待遍历的东西是一个数据范围,用xrange生成,从0开始,到end结束,步进为 opt.size。在循环体中--这也是python有意思的一个地方,缩进是语法要求,而不仅是为了美观--如果没有到最后一包,当前的这包就是字符串切割出来的。s[i:i+opt.size]表示切割s,从
i 切到 i+opt.size;如果不是最后一包,从i切到结尾,写作 s[i:]。python切割字符串的方法,还真是有C的风格,把字符串当成纯粹的容器/数组看待。4.6.2 标记还在循环里。63 # 标记64 subject = opt.subject_prefix + ' '
+str(i/opt.size+1)+'/'+str(end/opt.size+1) 65 header = 'To:' + to +
'n' + 'From: ' + user + 'n' + 'Subject:' + subject +' n' 66 current
= 'BODY_START:' + current + 'n' + 'BODY_END:NOTHINGGOESHERE' 67 print
68 print header第64行,生成主题subject,第65行,生成邮件头header,第66行,生成正文。第67和第68行,不是为了调试,而是为了避免用户在长时间切割的时候不知道跑了多远,还剩多远。这里输出的东西就是下面这段:To:[email protected] From: [email protected] Subject:[test-in] 2/3sent.其中,主题里的 [test-in]
是加的标记,包师弟接收的时候可以用这个标记过滤出我们特别的邮件。太阳底下无新鲜事,大毅同学提到在cisco设备中,vlan/trunk也使用了类似的方法做标记tag。后面的2/3表示共3包,这是第2包,用来在baoyu接收端拼接文件的时候作为顺序的依据,也用来显示出来,避免包师弟了解下载了多少,还有多少没下载。4.6.3 发送还在循环里。69 #发送70 msg = header + current 71 smtpserver.sendmail(user, to, msg)
72 print 'sent.' 73 time.sleep(sleep) 74 75 smtpserver.close()第70行,把邮件头和邮件正文拼在一起。这看起来是很天真的做法,邮件头和正文就这么就拼一起了啊?是的,是SMTP还是什么协议,就是这么规定的。好像head和body中间还有个回车。第71行,发送出去了。第72行,避免用户心急,程序把邮件发出去了要告诉用户一声。第73行,前面提到了,睡一下,避免SMTP服务器认为我们是发送垃圾邮件的坏人。第75行,离开循环,邮件都发送完了,断开连接。做事要有始有终,保持优雅。明天,或者后天,讨论一下接收端baoyu.py。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]