迟来的台湾自由行记录-续
接着述说从垦丁前往高雄的旅程.
10.4 早上在垦丁大街坐大巴前往高雄左营站, 可以直接上车买票, 达到左营后把包寄存在高铁站然后再骑车在高雄转了半天. 高雄作为一个港口工业城市并没有那么多旅游景点, 大概只有西子湾和旗津吧, 不过高雄有公共自行车可以使用, 只要有国际信用卡即可, 1小时内免费. 所以花个半天时间骑自行车闲逛是个不错的选择.
高雄捷运里面真是安静啊,只有零星的几个人, 大概不是高峰期吧, 下午3点左右

高雄捷运
出了捷运站有个台湾铁路发展的小展览馆:

火车头
参观完后在附近刷了信用卡借了一辆自行车, 骑到渔人码头:

停在码头的军舰

码头入口
旗津就是一块长方形的小岛, 不知道是不是人工的. 感觉很多设施还在建设中

旗津

接着换车继续去西子湾:

西子湾附近的中山大学, 无敌海景啊

西子湾日落

日落
西子湾是大陆旅游团的聚集地, 所以不想之前的地方, 这里人很多.

又见熟悉的人流
准备返回高铁站回台北了, 正值放学高峰期, 捷运里面好多学生, 很努力的的学生啊, 捷运上还在做功课 :

国中生放学
等候台湾高铁回台北, 这边的进站可以直接刷手机, 先进的吧:

高铁候车室
内部和国内差不多, 上座率比国内少的多, 速度基本稳定在290左右

高铁车厢内部
两个多小时后到达台北, 然后去宁夏夜市吃了点东西就会台北您好客栈了.

晚上11点后的台北捷运站
10.5 今天一个人打算自由闲逛, 租个单车转转, 不过台北的公共自行车普通的国际信用卡是刷不了的, 必须要晶片信用卡, 这个在国内好像不怎么多吧. 所以租公共自行车的计划失败, 然后跑去租那种山地车, 然后发现中午12:00到14:00是休息的, 于是悲剧的只好先去吃个午餐. 然后转到了行天宫附近, 不得不说台湾人真的很喜欢拜拜啊.

行天宫拜拜
吃完午餐, 突然天气转阴居然开始下雨了, 台北还真是如传说中一样, 全年大部分时间都在下雨, 刚刚还天晴来着. 趁着雨天去银行换了一些台湾货币:

台湾货币大全
其中有些市面上流通比较少的, 像那张200的绿钞和50的硬币在台湾这几天都没看到过.
等雨小了就跑去关渡码头租了一辆山地车, 沿着淡水河骑了1个多小时, 国际旅客要押护照, 大通证不行. 而且不能异地换车啊, 只能骑来回了.
说道骑单车, 台北淡水骑行体验太好了,沿河都是非常好的专门的骑行道,可以尽情的享受河岸风景。对于单车爱好者来说,这一点国内城市真的没法比。喜欢骑单车的应该安排一整天的单车行程哦.

淡水河沿岸风景

淡水河风景

淡水河风景

回程已是夜幕
还车之后直奔师大夜市, 我觉得这应该是我去过的几个夜市最好的了, 美女很多, 小吃也好吃, 大部分都是台湾本地人. 果然还是学校附近的夜市有活力.

师大夜市

这是招牌

吃饱喝足,赶往影视剧常出现的西门丁

入口, 繁华如上海

附近的西门红楼
据说红楼以前是唱歌演戏放片(含色情电影)的地方, 如今不知还在继续传统么.
西门丁步行区:

艺术家

步行区的人流
至此, 所有的台湾之行就差不多结束了, 明天一早就要飞回上海了.
台北桃园机场候机:

候机大厅
登机口都如此的有特色:

充满特色的登机口
此次台湾之行非常之满意,人少,风景好,服务热情,美食,这些都是值得称道的地方。下次有机会还想去台湾单车环岛.
迟来的台湾自由行记录
看不到图的可以去我的百度空间: http://hi.baidu.com/absolute8511/item/3b1bf9939e0e86de1e4271d4, 百度居然自动上传了我的网络图片转换成百度空间图片, 还屏蔽外链. 以后看来要先用wordpress写文章.
国庆去了台湾自由行,一直没有时间记录下来,眼看这新年都来了,还是抽出时间记录一下吧。图片很多,所以只能选部分了,完整的可以去相册里面看看。http://absolute8511.yupoo.com/
这次安排的是9.27到10.6号, 本来想玩到双十台湾国庆的,可惜没那么多时间了. 机票订的比较晚所以总共含税来回3224RMB, 上海到台北直飞, 如果你早点订可以少于2500, 甚至走香港中转的话可能可以2k以下搞定. 所以早打算比较好. 出行时间安排的话, 如果需要出海看大片的鲸鱼和海豚的, 应该安排在7,8月, 而国庆是不热不冷的季节,会比较舒服, 而且国庆大陆放假但是台湾那边是工作日,因此酒店费用会少些, 台湾出行的人也会少. 另外台湾冬天不会太冷, 因此跨年或者春节也是一个好的时候, 而5月春夏之交也是不错的时间.
去台湾自由行需要准备大通证, 入台证, 护照(有些酒店认护照不认大通证), 双币信用卡, 另外可以半个华夏的借记卡,可以在境外ATM上每天免费取一笔钱, 这次我基本没带什么现金, 基本都是用的这张卡取钱. 去之前要预定好各个地点的住宿, 高铁和台铁也可以网上预定, 台铁提前退票是不用手续费的. 高铁提前预定有早鸟优惠, 万一到了那里和安排冲突的话, 时间也可以改期, 只要补上早鸟优惠的金额即可. 去之前的事项就这么差不多了. 之后的事项会在后面提到的时候详细描述.
9.26 下午飞机直飞台北, 虽然起飞晚点, 但是到达还好, 5点多就降落到桃园机场了. 机场和国内的比起来气势没有那么强, 其实这边很多东西都是这样的, 并没有国内那种奢华大气之感, 而是充满了小家的温馨, 对传统文化的传承也绝对是比国内大城市好的多. 到达之后首先是在出口领取青年旅游卡, 这个卡将在后面的旅游景点发挥打折的作用, 只要你是未满30岁的青年都可以领取, 所以说早点出来闯荡是有好处地. 领取之后就是办个台湾的电话卡了, 有中华电信, 远程电信 , 台湾大哥大之类的, 都差不多, 如果需要上网, 可以办理套餐, 比国内的号码使用国际漫游便宜的多. 据我们几个人使用情况来看, 中华电信的信号应该是最好的. 然后机场大厅两侧有ATM取款机, 可以用银联卡取款, 我的华夏卡免手续费. 办理完这些后, 就可以坐机场大巴到达台北市中心了(悠游卡在地铁站办理即可 ). 大巴大概1个小时, 我们第一天住在龙山寺附近的芒果客栈, 一个非常小的但是很温馨的客栈, 会有些国际游客, 顶楼有阳台, 休闲吧等. 就算下雨了, 也可以在客栈和其他旅客闲聊玩上一天的地方.
当天晚上大家碰头在附近的華西街觀光夜市吃了点夜市小吃, 第一次和台湾的夜市亲密接触.
第二天清晨客栈附近:

在附近有个正宗的台湾手抓饼, 和大陆的基本差不多.
台北捷运, 抓拍到美女:

捷运出口有些小学生的涂鸦, 和谐的感觉:

先逛了国家大剧院, 中正纪念堂和自由广场, 都在一起

台北的道路, 绿化很好, 也很干净:

接着去了士林官邸, 老蒋一家子住的地方, 风景非常的好啊


上面一张颇有点XP的桌面背景的感觉.
是不是发现上面这些图里面都没什么人流, 这就是好处了, 大陆这时候人都在高速公路上堵着呢.
之后, 我们就出发去了故宫博物院, 由于不让拍照, 所以就没有照片了. 这里抱怨下台北的公共交通, 没有上海地铁那么方便, 台北捷运很多景点都没有, 而公交车基本是半个小时才一趟. 言归正传, 从博物馆出来后, 就直奔鼎鼎大名的士林夜市了.

我们去的是士林夜市地下一层的地方, 这边感觉都是游客来的, 因此没吃到什么好吃的, 真正好吃的都散落在士林各个小街道. 第一天结束~
9.28清晨在客栈附近闲逛, 发现这里附近有鸟市, 好多卖各种鸟的:

先去台北车站取票, 由于网上订票的时候大通证的填写有点问题导致折腾了好久, 网上买票的千万不要填写错了, 最好打印出来最后的订票信息.
这里不得不赞下车站的工作人员, 非常耐心和积极的为我们解决问题.
接下来去往闻名遐迩的国立台湾大学:

台大的建筑物都有点历史了, 风景也是不错的, 能在此深造乃人生福事.
抓拍校园美女:

台大附近貌似有名的奶茶店, 好多人:

接下来我们在台北漫步闲逛, 去往锵锵三人行提到的文艺的永康街:

非常安静闲适的地方, 台北很多这样满节奏生活的地方.
国父纪念馆前的广场, 很多欢乐的民众:

远处的101

台北的街道再来一张, 走在这样的街道真是心旷神怡啊:

低调的台北市政府, 据说进去还有机会和市长亲密接触还能拿到签名哦, 大家记得碰碰运气哈

101上看台北夜景:

之后奔向另一个夜市, 饶河夜市, 这个也是比之前的那个士林好多了, 很多人, 而且品种更多:

9.30 看看这边早餐都吃些什么呢:

今天一早要赶往花莲. 我们坐的太鲁阁号, 应该是最快的台铁, 速度大概80多, 沿途可以看到太平洋哦.

花莲这边可以选择民宿住宿, 民宿老板会帮忙安排一些行程, 很热情的服务.
老板先带我们去了一个私人领地:

住在这里的主人很幸福啊.
这一天刚好是中秋节, 第一次在国外过节, 台湾这边的中秋节大家会出来烧烤, 和大陆还是很不一样哈. 民宿老板组织大家一起吃烧烤, 有2个大妈级的香港同胞一起, 香港那边国庆+中秋只有3天假哦, 不过这些香港同胞都是思想好超前啊, 居然和我们这些80后也能聊起来.

10.1 在花莲民宿老板的介绍的包车司机的带领下, 把花莲的主要景点都转了转, 包括清水断崖, 太鲁阁, 七星潭. 一天搞定时间刚刚好.
包车司机以前可是空降兵哦, 牛逼的.





一整天后, 又在花莲的自强夜市解决了晚餐, 这几天可算是把台湾的夜市给体验了一把.
10.2 大早要赶往垦丁, 从花莲到垦丁将耗时5个多小时. 好在火车上一路有太平洋海景相伴.

下午2点左右到达预定的垦丁淳青背包客栈, 这个旅馆很小哦, 不过够便宜.

垦丁大街就在海边上, 还可以去吹吹海风, 晚上大街就是夜市了, 看到有人开着保时捷来, 拉风啊:

10.3 , 我们又包车了, 不过也可以租个电瓶车或者机车兜风. 垦丁建议两天, 第一天包车玩垦丁, 第二天可以出海, 我们时间太赶第二天就往高雄走了, 比较可惜.
垦丁大部分时间都是晴天, 记得擦防晒.
鹅銮鼻公园




这几天看海景都有点审美疲劳了. 到处都是无敌海景啊.
台湾最南点:

万里桐日落:

今天就结束了, 第二天赶往高雄了. 文章太长, 下一篇继续. :)
解决VPN断开后无法重连的奇怪问题
伤不起,大好佳节只能发个水文纪念。
言归正转,最近VPS搭建的VPN真心不稳定,断开后就连不上,非要重新启动ipsec服务。
网上搜了一下貌似出现的情况不是很多。看了下auth.log日志, 发现一处异常:
cannot install eroute, – it is in use for xxxx.
google上搜索发现貌似是openswan的一个bug,不过像是已经fix了,但我这还是会出现。
现象都一样,就是 reconnect will get a “cannot install eroute – it is in use for xx.xx.xx.xx”. restart the ipsec daemon then it works again. 重连失败需要重启ipsec服务。
然后,看到说可以改DPD参数,于是按照
http://linux.die.net/man/5/ipsec.conf 这说明改了下面几个参数
dpddelay Set the delay (in seconds) between Dead Peer Dectection (RFC 3706) keepalives (R_U_THERE, R_U_THERE_ACK) that are sent for this connection。
dpdtimeout Set the length of time (in seconds) we will idle without hearing either an R_U_THERE poll from our peer, or an R_U_THERE_ACK reply.
dpdaction :When a DPD enabled peer is declared dead, what action should be taken. hold (default) means the eroute will be put into %hold status, while clear means the eroute and SA with both be cleared. restart means the the SA will immediately be renegotiated, and restart_by_peer means that ALL SA’s to the dead peer will renegotiated.
dpdaction=clear is really only useful on the server of a Road Warrior config.
上面说的很清楚了,我试着将dpdaction=clear 加上,然后delay和timeout都设成5.
重启ipsec,终于稳定了。希望以后不要再有啥问题了。
上海-苏州-无锡-南京单车骑行游记
单车买了有段时间了, 一直都是周末周边骑骑短途, 这次清明特意叫上几个好友兼车友安排了此次长途骑行.
路线基本是沿着国道走, 国道线G312 ,在路上也碰到很多其他的车友, 走苏州, 无锡和南京的, 看来国道上的单车骑行还是挺多人的
路线图如下

走上海-苏州-无锡-南京那条红色的线路
4月2号早上8:00出门, 从杭州坐高铁到上海, 开始还担心不让自行车推上去, 不过后来拆了前轮或者折叠就能上了.
11点到上海, 等着上海的哥们汇合, 吃了点快餐, 快1点时从上海虹桥附近往苏州方向骑行了.
整个距离应该差不多80多公里, 晚上6点多达到了预定的酒店住下了
晚上在苏州逛了下
苏州历史文化街, 平江路

第二天早上继续出发, 在同德兴吃了面食, 味道不错

观前街门口排队不知道买啥好吃的

观前街, 不让自行车进, 所以就门口留恋下了

去往寒山寺的路上美景

传说中的寒山寺


来个正门

寒山寺完毕, 去往无锡

路上风景不错


快到无锡境内了

沿着运河一直走, 由于前晚天气突变, 风非常大, 据说有5级, 导致骑行速度一直停留在15以下, 严重影响了继续北上去南京的安排.
临时决定在无锡走太湖, 不继续骑到南京了, 晚上改坐高铁到南京继续南京城的骑行.


运河这段骑行很辛苦啊

转道去无锡太湖了

太湖旁边的蠡湖

赶上无锡樱花节了, 其实苏州, 无锡, 南京都有好多樱花


樱花


细节图

转道去往火车站搭高铁去南京, 往无锡城区方向
比想象中的繁华

大家的爱车

晚上10点才到预定酒店, 本来打算夜游秦淮河, 不过太晚就算了
第二天一早打算先南京城逛逛不能骑车的地方, 然后再骑自行车逛, 失策的是玄武湖居然是不让骑自行车的,
结果玄武湖就没进去看了.
中华门城墙


一些有特色的建筑

城墙

一路沿着城墙走到了武定门, 发现这边有个小门可以直接上城墙, 应该可以不用买门票的, 想上城墙的记得从这上啊

百闻不如一见的夫子庙

忒商业化了
秦淮河, 据说晚上好看很多, 估计以及没有了古时候的秦淮胭脂味了,古时候的文人真是日子过的文艺啊

夫子庙, 被门口的装饰完全挡住了

接着开始骑行了
这是南京的新地标么

非诚勿扰在这录的吧

南京的樱花, 风一吹, 散落一地, 非常美的意境

玄武门 , 玄武湖, 可惜单车进不去

总统府, 太多人了


南京长江大桥

准备回火车站返杭了


最后来张合影

不错的骑行旅游, 以后还会继续的
使用Python和vim插件结合让Vim支持多文件夹比较
在Vim的官方网站上有一个支持2个文件夹比较的插件DirDiff, 链接: http://www.vim.org/scripts/script.php?script_id=102. 不过仅支持2个文件夹, 我对齐进行研究并改进后让其支持多个文件夹的文件进行比较.
DirDiff插件的基本原理就是先生成要比较的几个文件夹中的所有文件列表文件, 该文件的每一行对应于一个文件以及它所在的文件夹. 启用文件夹比较模式时, 会载入这个列表文件, 当选中一行时会解析出文件路径, 然后以diff模式分别打开这个文件在不同文件夹下对应的文件进行比较.
这里为了方便, 我就使用Python来生成这个特定格式的文件列表, 然后启动vim 并启动文件夹插件比较.
Python脚本如下:
1 #!/usr/bin/env python
2 # coding:UTF-8
3
4 import os,sys,shutil,subprocess
5 from os import path
6 # 将dirlist中的目录列表下的文件放在一个文件词典filesdict中,
7 # 词典的key是dirlist中某个目录下的文件名(不含该目录名),
8 # value是dirlist中存在对应的key的所有目录
9 def getfilesfromdirs(dirlist):
10 filesdict = {}
11 for onedir in dirlist:
12 onedir = path.realpath(onedir) # 规范化目录名
13 #处理目标路径下(含子目录下)的所有文件
14 for root,dirs,files in os.walk(onedir):
15 # 记录每个文件名所属的目录,同名文件则会属于多个不同目录.
16 # 这样就生成了文件名到文件所在目录的倒排索引
17 for onefile in files:
18 # 若该文件名的键值还未创建则先创建
19 onefile = os.path.join(root,onefile)[len(onedir):]
20 if onefile not in filesdict:
21 filesdict[onefile] = []
22 filesdict[onefile] += [onedir]
23 return filesdict
24
25 def vimDirDiffN(diffdirs):
26 diffbuffer = './vimdirdiffntmpbuffer'
27 filesdict = getfilesfromdirs(diffdirs)
28 fileslines = []
29 for key,values in filesdict.iteritems():
30 fileslines += [' File: '+key+' @ ' + ','.join(values)]
31 write2fileline = str(len(diffdirs))
32 fileslines = '\n'.join(fileslines)
33 dirsymbol = 'A'
34 for onedir in diffdirs:
35 dirline = '<' + dirsymbol + '>' + '=' + onedir
36 write2fileline += '\n' + dirline
37 fileslines = fileslines.replace(onedir,'<' + dirsymbol + '>')
38 dirsymbol = chr(ord(dirsymbol) + 1)
39 write2fileline += '\n\n' + fileslines
40 fp = open(diffbuffer,'w')
41 fp.write(write2fileline)
42 fp.close()
43 subprocess.Popen('gvim -c ":DirDiffN ' + path.join(os.getcwd(),diffbuffer) + '"',shell=True)
44
45 if __name__ == "__main__":
46 if len(sys.argv) > 2:
47 diffdirs = sys.argv[1:]
48 for index in range(0,len(diffdirs)):
49 diffdirs[index] = path.realpath(diffdirs[index])
50 vimDirDiffN(diffdirs)
51 else:
52 print "Interactive Mode."
53 diffdirs = raw_input('input the dirs you want to diff(in List["A","B"]): ')
54 if diffdirs == '':
55 diffdirs = ['f:/PYOutput/old','f:/PYOutput/new','f:/PYOutput/third_merge']
56 else:
57 diffdirs = eval(diffdirs)
58 for index in range(0,len(diffdirs)):
59 diffdirs[index] = path.realpath(diffdirs[index])
60 vimDirDiffN(diffdirs)
61 raw_input('press to exit.')
这个脚本就是读入用户输入需要比较的文件夹列表, 然后扫描文件生成一个比较列表, 启动vim并执行我修改后的多文件夹比较插件DirDiffN.
修改后的DirDiffN插件比较多, 可以从附件下载. DirDiffN插件下载
将DirDiffN放入Vim的插件目录下即可.
效果预览图:
Windows安全机制
整个插件环境是和主程序隔离的,每个插件都使用一个独立进程,插件的宿主进程是一个进程外的COM组件,主进程启动宿主进程后,有宿主进程负责创建相应的插件对象,插件被创建起来后就在宿主进程中运行。为了保证插件不影响用户的系统,需要在宿主进程创建插件对象之前将宿主进程放进一个受限的沙箱环境中。
Windows的安全模型主要由2个部分组成, 一个是用于授权的Access Token,一个是用于保护安全对象的Security Descriptor。一个进程访问某个安全对象时,系统会使用对象的
Security Descriptor检查当前进程的Token是否有权限访问该对象。
Access Token包含了一些SID用于标示它拥有的安全身份,另外还包含一些Privilege信息以及其他授权信息。
Security Descriptor包含了用于控制访问权限的DACL列表以及用于审核的SACL列表。ACL列表是一系列的ACE信息,每个ACE包含了某个SID的访问权限,当一个进程访问一个对象时,系统会逐个检查对象的ACE项,如果该进程的Token中包含的SID匹配ACE中的SID,那么系统就会执行ACE中对该SID的访问控制操作(拒绝或者允许),需要注意的是系统是按照列表从头到尾的顺序逐个检测ACE,一旦有拒绝或者允许的匹配项,都会立刻停止检测后继的ACE项。(除非token中有指定RestrictedSID).
下图是2个不同线程访问一个安全对象的过程:
关于Windows安全机制,它提供了几种机制来确保安全性,主要有RestrictedToken,Job Object,Alternate Desktop,以及在Vista引入的IntegrityLevel的方案来简化和加强
Windows下的安全隔离。
由于XP,和XP以上的系统在安全机制上的一些区别,不得不做2种不同的处理。在XP系统下,主要使用Job以及其安全属性,使用JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JOBOBJECT_BASIC_UI_RESTRICTIONS以及JOBOBJECT_SECURITY_LIMIT_INFORMATION设置一个受限的JOB并将进程放入该Job中,同时还要使用AdjustTokenPrivileges将进程的一些Privilege信息删除。而在Vista以后的系统中,无法使用JOBOBJECT_SECURITY_LIMIT_INFORMATION设置Job的安全属性,改用IntegrityLevel将进程的安全级别设置为Low。
在上述的受限环境中,进程的写权限几乎被完全禁止了(除了设定为较低安全级别的对象),仅剩下读权限,这样基本能防止插件对系统造成损害了。
当然,在这种受限环境下,经过测试,XP系统下的COM进程间通信会有一些问题,而Vista下的IntegrityLevel似乎对这种情况专门做了处理,因此发现vista下在受限环境下的COM进程间通信一切顺利。为了处理XP下在受限环境下的COM调用和注册,引入一种COM的免注册方案,即Registration-Free 技术。主要就是利用manifest文件让COM的注册脱离注册表依赖。关于Reg-Free技术参考文献有2篇文章写的已经很详细了。需要注意的是,XP和Vista之后的manifest文件的都去顺序问题,XP系统是先尝试读取外部manifest文件,没找到才尝试读取dll文件本身嵌入的manifest资源,而vista之后刚好反过来了。另外,进程外的COM组件是不支持Reg-Free的。(经测试,XP下使用reg-free的方案好像只能解决COM进程内的接口调用,对于进程间的接口调用还得另做处理。)
最后,还有一个需要注意的是Win7下的Job处理,由于Win7下的explorer进程会将进程放入一个PCA的Job中,为了避免使用我们自己的Job失败,我们需要防止Win7的这种自作主张的行为,需要在manifest文件中加入以下内容,
<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>
<assembly xmlns=”urn:schemas-microsoft-com:asm.v1″ manifestVersion=”1.0″>
<v3:trustInfo xmlns:v3=”urn:schemas-microsoft-com:asm.v3″>
<v3:security>
<v3:requestedPrivileges>
<v3:requestedExecutionLevel level=”asInvoker” uiAccess=”false” />
</v3:requestedPrivileges>
</v3:security>
</v3:trustInfo>
<compatibility xmlns=”urn:schemas-microsoft-com:compatibility.v1″>
<application>
<!–The ID below indicates application support for Windows Vista –>
<supportedOS Id=”{e2011457-1546-43c5-a5fe-008deee3d3f0}”/>
<!–The ID below indicates application support for Windows 7 –>
<supportedOS Id=”{35138b9a-5d96-4fbd-8e2d-a2440225f93a}”/>
</application>
</compatibility>
</assembly>
关于Windows安全方面更多详细的资料可以查看以下参考文献。
参考文献:
http://msdn.microsoft.com/en-us/library/aa379570(v=vs.85).aspx
http://www.tenouk.com/ModuleH.html
http://msdn.microsoft.com/en-us/library/aa480244.aspx
http://www.google.co.uk/patents/about?id=m40IAAAAEBAJ
about COM Reg-Free,
http://blogs.msdn.com/b/junfeng/archive/2006/05/17/registration-free-com-net-interop.aspx
http://msdn.microsoft.com/en-us/library/ms973913.aspx
http://msdn.microsoft.com/en-us/magazine/cc188708.aspx
使用某个文件夹下的所有文件去替换另一个文件夹下及其子文件夹下存在的同名文件(Python实现)
值此新年即将到来之际,在这献上今年最后一篇文章.
产生这个需求是在项目的一次图标替换上,当时给了我一堆新图标要替换原来的老图标,可是原来的老图标分布在某个文件夹下的各个子文件夹下面,而新图标全是在同一个目录下的. 手动替换的话,只能是搜索文件名后替换,但是文件很多太麻烦了,没找到现成的工具可以实现我的需求.于是有了下面这个脚本,正好熟悉下刚刚学会的Python. 如果有人知道有什么工具可以完成的话不妨留言告知:).
下面脚本实现的就是在dest目录及其子目录下面,寻找和src目录下的文件对应的同名文件,如果找到唯一的一个同名文件,用src里面的新文件替换dest里面对应的老文件. 如果没找到同名或有多个同名的,就忽略.因为这种情况下需要人工接入是否替换,不过这样工作量已经少了很多了.
代码通过扫描一遍dest目录及其子目录,建立了以文件名为索引,文件所在目录名为键值的倒排索引. 然后对src目录下的每个文件名去刚刚建立的倒排索引中寻找键值,如果键值中刚好只有一个目录名,说明找到了对应的唯一同名文件,替换之.其他的忽略.
代码如下:
代码
#!/usr/bin/env python
# coding:UTF-8
import os,sys,shutil
from os import path
def findandreplace(src,dest):
srcfiles = os.listdir(src)
destfilesdict = {}
#处理目标路径下(含子目录下)的所有文件
for root,dirs,files in os.walk(dest):
# 记录每个文件名所在的路径,多个同名文件则会有多个不同路径.
# 这样就生成了文件名到文件所在路径的一个倒排索引
for onefile in files:
# 若该文件名的键值还未创建则先创建
if onefile not in destfilesdict:
destfilesdict[onefile] = []
destfilesdict[onefile] += [root]
multisamename = []; # 存储目标目录及其子目录下有多个同名文件的文件名
for srcfile in srcfiles:
fullsrcfile = os.path.join(src,srcfile)
if os.path.isfile(fullsrcfile):
if srcfile in destfilesdict:
if len(destfilesdict[srcfile])>1:
multisamename += [srcfile]
else:
# 有且只有唯一的一个同名文件,那么肯定是要替换的那个
shutil.copy(fullsrcfile,destfilesdict[srcfile][0]+’/'+srcfile)
print srcfile + ‘ replace success.’
print ‘following files has more than one in dest directory, replace skipped.’
print ‘\n’.join(multisamename);
if __name__ == “__main__”:
args = sys.argv
if len(args) > 2:
src = args[1]
dest = args[2]
print “all files under the “+dest+\
“(including the subdirectory) will be replaced by the files under ” +\
src+” where they have the same name.”
if raw_input(‘Sure(y/n?): ‘) == ‘y’:
findandreplace(src,dest)
else:
print “Not enough arguments!”
测试代码如下:
代码
#!/usr/bin/env python
# coding:UTF-8
import os,sys
import shutil
import findandreplace
rootdir = ‘d:/test/’
testsrcdir = ‘testsrc’
testdestdir = ‘testdest’
testfile = { ‘notexist’ : ['001','002','003','004','005'], # 替换目标不存在的文件
‘onlyone’ : ['101','102','103','104','105'], # 有唯一对应的文件存在的
‘morethanone’:['201','202','203','204','205']} # 多于一个同名存在的
testfileext = ‘.txt’
# clear old test files
shutil.rmtree(os.path.join(rootdir,testsrcdir),True)
shutil.rmtree(os.path.join(rootdir,testdestdir),True)
# generate src files
os.makedirs(os.path.join(rootdir,testsrcdir))
for key,values in testfile.iteritems():
for filestr in values:
srcfile = open(os.path.join(rootdir,testsrcdir,filestr+testfileext),’w')
srcfile.write(filestr+’srcfile’)
srcfile.close()
# generate dest files
os.makedirs(os.path.join(rootdir,testdestdir))
for key,values in testfile.iteritems():
if key == ‘notexist’:
pass
elif key == ‘onlyone’:
for filestr in values:
newdir = os.path.join(rootdir,testdestdir,filestr)
os.makedirs(newdir)
srcfile = open(os.path.join(newdir,filestr+testfileext),’w')
srcfile.write(filestr+’destfile’)
srcfile.close()
elif key==’morethanone’:
for filestr in values:
newdir = os.path.join(rootdir,testdestdir,filestr)
os.makedirs(newdir)
srcfile = open(os.path.join(newdir,filestr+testfileext),’w')
srcfile.write(filestr+’destfile’)
srcfile.close()
srcfile = open(os.path.join(rootdir,testdestdir,filestr+testfileext),’w')
srcfile.write(filestr+’destfile’)
srcfile.close()
findandreplace.findandreplace(os.path.join(rootdir,testsrcdir),os.path.join(rootdir,testdestdir))
Python真是提高效率的利器哈.
