-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathftputil-introduction.html
112 lines (109 loc) · 9.27 KB
/
ftputil-introduction.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<!DOCTYPE html>
<!--[if IE 8]> <html class="no-js lt-ie9" lang="zh-cn"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="zh-cn"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>道可叨 | ftputil 简介 </title>
<meta name="viewport" content="width=device-width">
<meta name="author" content="Qiang">
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
<link href="http://localhost:8000/feeds/atom.xml" type="application/atom+xml" rel="alternate" title="道可叨 Atom Feed" />
<link rel="stylesheet" href="https://zhuoqiang.github.io/theme/css/app.css">
<script src="https://zhuoqiang.github.io/theme/js/vendor/custom.modernizr.js"></script>
</head>
<body>
<header>
<hgroup>
<a href="https://zhuoqiang.github.io">
<h1 i18n>道可叨</h1>
<h2>Free Will</h2>
</a>
</hgroup>
</header>
<section>
<article>
<header>
<h1><a href="https://zhuoqiang.github.io/ftputil-introduction.html">ftputil 简介</a></h1>
</header> <div>
<section>
<p>最近工作上需要定制一个 FTP 客户端工具,用来同步本地文件夹到 FTP 服务器上。这般粗活首选当然是 Python: 开发迅速,编写简洁,还能用 py2exe 打包独立分发。</p>
<p>但 Python 标准库对 FTP 的封装太底层,很不好用。在自己动手改进之前先放狗搜了一下,果然早有人忍不住,不但封装了 FTP 客户端,而且开源了。这就是 <a class="reference external" href="http://ftputil.sschwarzer.net">ftputil</a> ,一个 Python 高层次接口 FTP 客户端库。</p>
<p>ftputil 的接口非常简单易用。一个 <tt class="docutils literal">ftputil.FTPHost</tt> 对象就包括了 FTP 的上传下载和查询。整个接口还刻意模仿标准模块 <tt class="docutils literal">os</tt> 的本地文件操作接口,上手不费吹灰之力。与 <tt class="docutils literal">os</tt> 模块的文件操作接口保持一致还有个好处: 多态。本地文件和 FTP 远程文件操作接口一模一样,这样对已有的程序添加 FTP 存储支持,只需要把 os 模块换成 FTPHost 对象就成了。FTP 的操作对调用端代码是透明的,非常方便。</p>
<p>ftputil 还有个隐藏功能:对本地和远程 FTP 文件夹进行同步。也许作者认为这个功能还不成熟,并没在文档中提及。不过文件夹同步恰好是我需要的,自然毫不客气直接拿来使用!ftputil 源代码中的 <tt class="docutils literal">ftp_sync</tt> 实现了同步功能。下面几行代码就实现了将本地文件夹同步到 FTP 服务器</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">ftputil</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">ftputil.ftp_error</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">ftputil.ftp_sync</span> <span class="kn">import</span> <span class="o">*</span>
<span class="k">def</span> <span class="nf">sync</span><span class="p">(</span><span class="n">local_directory</span><span class="p">,</span> <span class="n">ftp_host</span><span class="p">,</span> <span class="n">remote_path</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">with</span> <span class="n">FTPHost</span><span class="p">(</span><span class="n">ftp_host</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span> <span class="k">as</span> <span class="n">remote</span><span class="p">:</span>
<span class="nb">print</span> <span class="s1">'Login to FTP </span><span class="si">%s</span><span class="s1"> successfully as user </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="p">(</span><span class="n">user</span> <span class="ow">and</span> <span class="n">user</span> <span class="ow">or</span> <span class="s1">'anonymous'</span><span class="p">))</span>
<span class="n">local</span> <span class="o">=</span> <span class="n">LocalHost</span><span class="p">()</span>
<span class="n">syncer</span> <span class="o">=</span> <span class="n">Syncer</span><span class="p">(</span><span class="n">local</span><span class="p">,</span> <span class="n">remote</span><span class="p">)</span>
<span class="n">syncer</span><span class="o">.</span><span class="n">sync</span><span class="p">(</span><span class="n">local_directory</span><span class="p">,</span> <span class="n">remote_path</span><span class="p">)</span>
</pre></div>
<p>本来要自己实现的功能几行代码就搞定,真省事。</p>
<p>虽省事,却不省心,测试时发现了两个问题:</p>
<ul class="simple">
<li>FTP 服务器上以 <tt class="docutils literal">.</tt> 开头的隐藏文件无法例出。解法是给 FTP 命令 <tt class="docutils literal">LIST</tt> 加上参数 <tt class="docutils literal"><span class="pre">-a</span></tt> 显示所有文件</li>
<li>从 Windows 平台同步文件夹时,Windows 的文件分隔符 <tt class="docutils literal">\</tt> 被 FTP 服务器直接当做文件名的一部分,导制文件没有在目录下创建,而是新建另一个名为 <tt class="docutils literal">dir\file.name</tt> 的文件。解法是使用 FTP 命令之前,先把路径中的文件分隔符替换成通用的 <tt class="docutils literal">/</tt>。</li>
</ul>
<p>这两个问题我遇到了,修好了。本着人人为我我为人人的开源精神,我给作者提了两个 bug (<a class="reference external" href="http://ftputil.sschwarzer.net/trac/ticket/62">#62</a>, <a class="reference external" href="http://ftputil.sschwarzer.net/trac/ticket/63">#63</a>),并跟作者一起在 ftputil v2.7 中修好了这两个问题。ftputil 的作者 Stefan 很好沟通,一点举手之劳赢得他的感谢,还挺有成就感的。</p>
<p>天下程序一大抄,看你会抄不会抄。不会抄的,键盘上的 <span class="kbd">ctrl</span> <span class="kbd">c</span> <span class="kbd">v</span> 键一定是饱经风霜了吧; 会抄的,在发明轮子前,先找现成的轮子,找到了,会用了,从此工具箱中又多了一件趁手的兵器。这不比毫无积累的复制粘贴大法高出不少吗; 如果能再进一步,不怕麻烦,帮着修补轮子,让它更加结实好用,利人利己,也算是抄亦有道了吧。</p>
<p>谢谢 Stefan 给 Python 社区贡献的好轮子!</p>
</section>
</div>
<footer>
<p>
<time datetime="2012-06-12T23:23:00+08:00" pubdate>2012-06-12</time><a href="https://zhuoqiang.github.io/category/programming.html"><span class="category" i18n>programming</span></a>
</p>
<ul>
<li><a href="https://zhuoqiang.github.io/tag/opensource.html"><span class="tag" i18n>opensource</span></i></a>
<li><a href="https://zhuoqiang.github.io/tag/python.html"><span class="tag" i18n>python</span></i></a>
</ul>
</footer><link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk@latest/dist/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script type="text/javascript">
var gitalk = new Gitalk({
clientID: "2f60008869581fd61d19",
clientSecret: "6b303dcf58c04cd35782bae82540921663cbfda8",
repo: "zhuoqiang.github.com",
owner: "zhuoqiang",
admin: ["zhuoqiang"],
id: "ftputil-introduction",
title: "ftputil 简介",
perPage: 30,
distractionFreeMode: true,
pagerDirection: "last",
});
gitalk.render('gitalk-container');
</script></article>
</section>
<footer>
<p>@ <a href="mailto:[email protected]"><span i18n>Qiang</span></a> | <span class="heart"><a href="https://github.com/getpelican/pelican">Pelican</a> & <a href="https://bitbucket.org/zhuoqiang/jing">Jing</a></span></p>
</footer>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js"></script>
<script>window.jQuery || document.write('<script src="https://zhuoqiang.github.io/theme/js/vendor/jquery-1.8.3.min.js"><\/script>')</script>
<script src="https://zhuoqiang.github.io/theme/js/vendor/moment.min.js"></script>
<script src="https://zhuoqiang.github.io/theme/js/vendor/moment-lang.min.js"></script>
<script src="https://zhuoqiang.github.io/theme/js/vendor/i18next-1.6.0.min.js"></script>
<script src="https://zhuoqiang.github.io/theme/js/main.js"></script>
<script type="text/javascript">
var GoSquared = {};
GoSquared.acct = "GSN-743443-H";
(function(w){
function gs(){
w._gstc_lt = +new Date;
var d = document, g = d.createElement("script");
g.type = "text/javascript";
g.src = "//d1l6p2sc9645hc.cloudfront.net/tracker.js";
var s = d.getElementsByTagName("script")[0];
s.parentNode.insertBefore(g, s);
}
w.addEventListener ?
w.addEventListener("load", gs, false) :
w.attachEvent("onload", gs);
})(window);
</script>
</body>
</html>