用Python实现FTP文件上传

前情

最近在做活动编辑器的时候,考虑到运营人员很多都没有图片上传的权限,所以想在活动编辑器里面内置一个这样的功能,让运营可以使用上传控件或者托拽的方式上传图片到服务器,并在上传成功之后,自动把地址放到文本框里。

第一步要做的就是尝试着实现用FTP来上传一个文件到服务器的指定目录,同时基于文件的sha1值来命名上传之后的文件。

手上现有的两种实现路径是NodeJsPython,不过想到最近刚学Python,正需要这样一个机会,就先尝试python的方式。

开发

先是Google了一下,知道了一个ftplib的内置模块可以用来做FTP相关的功能。然后是之前在即刻上有看到余弦发的一个文章,说到用Python一句话查看文件的哈希值,上去找了找,也很快找到了那篇文章里面的相关代码。

折腾一下之后,实现代码如下:

import ftplib
import hashlib
import os

host = 'YOUR HOST'
username = 'YOUR NAME'
pwd = 'YOUR PWD'
port = 21
filePath = 'some/path/to/img.jpg'
serverPath = '/where/to/store/your/file/on/the/server/'

session = ftplib.FTP()

session.connect(host, port)

session.login(username, pwd)

session.cwd(serverPath)

file = open(filePath, 'rb')

filename, file_extension = os.path.splitext(filePath)

str_hash = hashlib.sha1(file.read()).hexdigest()

target_file_name = str_hash[:16]+file_extension

session.storbinary('STOR '+target_file_name, file)

file.close()

session.quit()

代码写完,就顺手执行看了下效果:文件顺利按的传到了预设的目录,也重命名为了指定的文件名。但是,文件的体积是0

调试

在Python的IDEL环境里面使用help命令查看了file相关的各种文档,最后把问题的方向指向了file.read。因为当时在IDEL环境里面,使用file.read读取了要上传的文件内容之后,再次调用file.read时,返回的内容为空。

于是在Google上面用python file read twice作为搜索词搜索了一下。果然找到了问题,文件里面有一个指针指向上一次读取的位置,默认是在最开始,也就是0。file.read会读取文件的全部内容,完成之后,指针就指向文件的最末尾。

所以,在调用过一次file.read之后,再次调用file.read,会从文件最末尾开始获取内容,这获取的内容自然就是空了。而ftp.storbinary在上传文件的时候,内部应该也是会使用类似file.read类似的方法来获取要上传的文件内容并传递给服务器。这个时候也自然就没法正常获取正确的文件内容

解决方式是在file.read之后,使用file.seek(0)来把文件的指针指回最开始。

最终代码:

import ftplib
import hashlib
import os

host = 'YOUR HOST'
username = 'YOUR NAME'
pwd = 'YOUR PWD'
port = 21
filePath = 'some/path/to/img.jpg'
serverPath = '/where/to/store/your/file/on/the/server/'

session = ftplib.FTP()

session.connect(host, port)

session.login(username, pwd)

session.cwd(serverPath)

file = open(filePath, 'rb')

filename, file_extension = os.path.splitext(filePath)

str_hash = hashlib.sha1(file.read()).hexdigest()

target_file_name = str_hash[:16]+file_extension

# 前面的file.read使得file的read cursor指向了文件的尾部
# 如果不手动调整指针的话,后面的文件上传,就会是一个空文件
file.seek(0)

session.storbinary('STOR '+target_file_name, file)

file.close()

session.quit()

参考文档

  1. Python Script Uploading files via FTP
  2. Extracting extension from filename in Python
  3. Why can’t I call read() twice on an open file?
  4. 我是如何 Python 一句话校验软件哈希值的

关于我的口才

之前看曹政的书《你凭什么做好互联网》,里面关于技术人员有一个描述

大部分技术人员分享时候的盲区,自说自话,完全不考虑受众

这里摘取的不全面,不过大体意思是有的,就是很多技术人员会有的糟糕的口才,而我,正巧,也是其中一员。

不同于写作,演讲、分享、辩论,这些口语形式的思想表述,需要你在很短的时间同时掌控好思维和舌头,流畅的展现你的思想,没有编辑的概念。

而我总是想的太快,舌头跟不上,说出来的话和自己真实想表达的意思要打个折。大信息量的涌入使得舌头的性能降低,说出来的话还会有点口齿不清。

很早就意识到这个问题,可是却难有改观。

比如这次的一个活动页开发

因为业务逻辑和交互复杂的不输于一般的单页面应用,所以一改以往收集DOM操作为一个动作的抽象方式,这次用了MVVM架构的一些数据驱动视图的思路,同时还基于Redux的思想做了数据的管理。一番调整之后,自己还是有点小得意的,DOM操作和VM的完美结合。

再说点尴尬的背景,这个活动分移动和PC两个页面,功能一样,UI大体也是类似,但是却由我和同事小磊分别开发……

我知道这是一件很没脸说的事情,两个有经验的前端做了这样没动脑子的决定。虽说我是后加入这个活动开发的,可是在参与进来的时候,花一两小时好好熟悉一下项目,然后再一起讨论分工合作是一个完全合理而且必要的流程。

继续说前面的调整,因为那点小创意,所以我在开发进度上有点领先(UI和很多前期代码是直接从小磊那边拷贝过来的)。小磊那边在管理UI上的数据变动这块遇到了一些问题,业务逻辑有点复杂,各种弹窗,还有多个模块之间的数据通信,纯DOM操作对于掌控全局变化就有点吃力。

这时候为了进度,我尝试跟小磊介绍一下我的处理问题的思路。我想跟他说数据驱动,订阅者,MVVM,React,Redux……

是的,面对一个分享将会带来的荣耀,我一瞬间就想了这么多。打开我的代码,开始了介绍:“这个活动很复杂,所以咱们得用数据驱动的方式开发,你看我这个dataCenter,我把数据都放这里面用getter和action维护,然后action里面发布事件,再看这块,main这块,对数据更新做了响应。再看这块,抽奖回调里面调用action来更新数据。还不错吧,其实这个是借鉴redux里面的思想,store”。话没说完,小磊同志不耐烦了:“越说越懵,所以我这个问题该怎么解决?”

尬了一下,小磊向来耿直。

“那就先不看我这个实现,你这现在是哪有问题了”。是的,我还没弄清楚具体哪出问题了。

后面仔细看了看小磊的代码,指出了一些模版里面基于数据的逻辑判断问题,再给了一个全量更新列表模版(数据量少,就几条)的思路,总算是博得一句“哦,原来这样啊”

一点总结

伤痛中总是伴随着成长,不好好想想说出去的话,早晚是会遭殃。

在这件事上总算对自己糟糕的口才又有一次认识,也知道区分在什么场景下做技术分享,什么场景下是bugFix。做技术分享要精要细,bugFix就不要废话太多,讲究快准狠,以解决问题为只要目的。

PS:值得安慰的事第二天一上班,小磊就过来说:“我昨天晚上仔细想了想,你的那个dataCenter真是太有必要了”

前端同学关于活动页面设计的一些建议

这个是在一次加班加点完成活动之后,发给设计同学的一个建议,放上来,给大家也看看

以下是原文:

建议的目的:主要是希望通过在设计上的调整,能让前端这边轻松快速的完成活动页的切图部分。一个活动,特别是现在的移动端活动,前端的很多精力都会花费在切图上。

一些事先定义:

前端这边切页面,特别是活动页面,对于一些描述性的不会变动的内容,会切成图片。

对于一些有交互效果,内容会随着时间或者用户操作变化的内容,比如排行榜,比如登录和非登录状态的切换展示区域,比如一些弹出层,是需要切的非常细致。这样才能适应需求的灵活性。

所以希望设计同学们在设计的时候,千万留意则个。在不会变动的区域,可以任意发挥。但是在会变动的区域,则尽量能考虑一下下面的建议。

后面的内容区域特指内容会变动的部分。

背景

背景这块,在页面顶部可以自由发挥,到时候前端直接横切就可以。但是到内容区域之后,就需要注意了。

第一个是,尽量让变动区域和非变动区域之间,没有图像上的连接。因为背景的居中和内容的居中,浏览器的计算方式会有些不一样。如果变动区域和非变动区域必须严密对齐才能好看,就会比较麻烦。

第二个是:在内容区域的左右背景,最好能不要有超出内容区宽度范围的装饰性的图案,这个是可以有,不过切起来麻烦,还望手下留情。

第三个:整个内容区域的背景,如果不是效果需要,尽量保证颜色是一致的,不要渐变也不要分块的颜色。这样就可以不用切背景图,直接用css写一个颜色值实现。

字体

好看的字体是好看,不过在内容区域,文字是直接写上去而不是却的图片。这个时候,就不能肆意的使用字体。

设计的系统上会安装几百个字体。可是大部分的用户的系统上并没有。如果前端按照psd上面的要求设置了一个生僻的字体,在用户那边的效果就没法和设计稿保持一致,甚至会有很大偏差。

微软雅黑,tahoma,arial,Hiragino Sans GB,宋体

这个是前端这边,目前设置的字体展示优先级。设计同学在做内容区这块的时候,字体尽量就用上面这几种。因为他们的安装量比较大,可以保证在大部分用户的浏览器上的展示效果。

按钮

按钮这块,主要的也是字体问题,尽量不要字体的阴影和描边。

另外就是按钮的风格和尺寸,尽量统一,这样前端就可以只切一个按钮然后导出应用。按钮的背景,如果可以的话,就不要渐变色和阴影。这样前端图片都不用切,直接用css就能画出相同效果的按钮了。

移动端设计要注意的一些问题

这块指的web的移动端。原生的可能会有不一样的地方

设计稿的尺寸750

移动端,因为我们的框架的问题,设计的时候最好用750px作为宽度,这样我们好进行自适应的配置。

设计风格简洁

移动端,跟PC的设计有些不一样的地方就是,它的布局不是固定的,会随着用户屏幕的不同,做对应的调整,也就是自适应。

在自适应这块,用css来做比较好,用图片就比较麻烦。因为图片的放大缩小,有些时候不是那么尽如人意的。所以在移动端的活动页面,在内容区域,除非是奖品图,头像等内容性质的图,否则一些装饰性的内容,尽量简洁一点,这样前端就好用css来实现了

布局,多排,不要多列

自适应面对的主要问题就是宽度的变化。而宽度影响最大的就是多列内容的布局。

为了能快速进行活动页面的开发,设计同学在设计活动页面的时候,就尽量减少内容的分列,改列为排。

这样处理起来就比较轻松了。

React入门实例教程读书笔记

这份读书笔记是看了阮一峰的《React 入门实例教程》之后撰写的,留作记录。需要看原文的可以点击前面的书名访问对应链接。

这篇文章的目的

  • 介绍react
  • 如何下载react
  • 如何安装react
  • 如何使用react

文章的组织架构

从易到难的开始介绍。

react在页面的部署

  1. 依赖的两个js
  2. jsx 模板的标签规范
  3. 模板的编译应该放到服务器完成

模板语法

  1. React.render() 转换模板为HTML并插入节点
  2. 允许HTML和javascript混写。
    1. 规则是:遇到HTML标签(以<开头)则视为HTML,遇到代码块(以{)开头,视为javascript
    2. HTML内容可以直接写在javascript变量里
    3. javascript变量可以直接插入到模板。如果变量是数组,则自动展开这个数组的所有成员

组件

组件介绍

  1. 用React.createClass来生成组件类
  2. createClass的传参对象,需要一个render方法,用来描述组件的渲染
  3. 组件类以大驼峰方式书写
  4. 组件类以模板的方式调用,写法可以有单标签和双标签两种
  5. 组件类以模板的方式调用,实际是实例化了产生了一个对象,以下简称为组件
  6. 组件的调用和HTML标签完全一致,能加入属性。属性的调用,可以通过组件类的实例在javascript中,以this.props.xxx的方式调用
  7. 组件的style属性设定的时候,期望的值是一个对象{opacity: 0.5, marginLeft: ‘1px’} 而不是一个字符串,最终的写法是{{opacity: 0.5, marginLeft: ‘1px’}} 外面一对大括号表明是javascript代码块,里面的一对大括号,表明是对象
  8. 冲突的属性名class和for 要对应改为className和htmlFor,因为class和for是javascript的保留字
  9. this.props的属性和组件HTML属性一一对应,但是this.props.children例外,它表示组件的子节点
  10. 在用双标签的方式调用组件的时候,标签之间的HTML即为组件的子节点,完全和原生HTML一致

组件的特性

  1. findDOMNode
    1. virtual DOM
    2. virtual DOM 通过 DOM diff算法映射到真实DOM上
    3. findDOMNode用于获取跟组件关联的真实DOM的节点
    4. 只有在virtual DOM插入文档之后才能起作用
  2. this.state
    1. 类似状态机的概念
    2. getInitialState方法来设定初始状态
    3. 通过用户互动修改状态,一般是对应的event function来setState
    4. render里面,根据不同的状态渲染出不同的UI
    5. setState自动调用render重绘UI
    6. 区分this.props和this.state: this.props类似常量,设定之后不改变;this.state是随着用户互动而变化的特性
    7. 表单内容的变化也是通过state来进行更新的

组件生命周期

  1. 三个状态
    1. Mounting 已插入真实DOM
    2. Updating 正在被重新渲染
    3. Unmounting 已移出真实DOM
  2. 每个状态提供两个回调函数,will在进入状态之前调用,did在进入状态之后调用
  3. 三个状态共计五种回调函数,书写方式component是前缀,will/did是行为,Mount/Update/Unmount是状态
    1. componentWillMount()
    2. componentDidMount()
    3. componentWillUpdate(object nextProps, object nextState)
    4. componentDidUpdate(object prevProps, object prevState)
    5. componentWillUnmount()   为什么没有componentDidUnmount() ?
  4. 特殊状态的回调
    1. componentWillReceiveProps(object nextProps) 已加载组件收到新参数
    2. shouldComponentUpdate(object nextProps, object nextState) 组件判断是否重新渲染时调用 不明白

结合其他库或者框架使用

  1. react没有任何依赖
  2. react只关注表现层
  3. 如果希望对组件的DOM进行操作,尽量在componentDidMount中进行,保证真实DOM已经存在

主旨

React是一个关注表现层,以组件来构建内容,以状态机来完成交互的UI改变的,可以在浏览器端和服务器端同时运行的前端框架。

关于数据备份

讲述了笔者悲催的数据恢复的过程以及一些痛过之后对数据备份方面的经验

凄惨的经历

一杯水引发的惨案

今天在公司上班,因为干活比较用心,喝水的时候也盯着电脑,喝完之后就随便把杯子放笔记本边上,结果一个不小心,水就撒了一部分到键盘上。当时没怎么在意,随便拿个餐巾纸吸掉表面的水就继续干活,顺便跟个妹子聊天。

结果没两分钟,开始不对劲了,在编辑器里面,一直在触发换行,换别的软件获取焦点之后也是这样——原来是Enter键出毛病了,连按了几次之后,Enter事件不再被触发,但是按Enter键也没得效果。这个时候知道事情大条了,赶紧找公司的网管救命。

网管知道经过之后,一脸佩服的看着我,一般人电脑进水之后都是立马断电源拔电池的,我倒好,还这么悠闲的跟妹子聊天…..

检查的结果很不理想——就是网管也不知道是哪出问题了,但是帮我把键盘进水的键拔出来仔细擦干了藏在内里的水,然后告诉我:去维修点修吧,要是还在保修期,千万别说是进水了,不在维修期待话,破费一笔是难免的。

当时我对破费一笔的概念还停留在两三百多境界。

辛酸的维修过程

公司在中关村,经过网管指点,找维修点倒也简单,在鼎好电子商城的地下二层,A001就是(话说对于我后来修电脑的地方到底是不是联想到官方维修店,我是有点怀疑的,因为我找到了A005,A004,按照摊位的延续,到那家店也差不多是A001,可是偏偏那个店没在店名上挂个联想的名字或者logo,也没有牌子表明序号)。

在维修点,维修人员弄个仪器左测测右弄弄。在那个时候,我的心情还是比较悠闲的,因为两三百块钱虽然很心疼,但还是能接受的,我就在他们检测的时候在一边拿手机看小说去了。最后,给出个答案——硬盘损坏

话说这个解释一出来,我挺惊讶的,报修的时候按照网管的指点,我没说是电脑进水而是说突然的就这么开不了机,反正怎么显得自己小白就怎么说,这样保修的时候可以避免自身的责任。可是硬盘损坏,这个跟进水貌似没有什么关联。我有点怀疑对方是不是想坑我的钱,就拿出一个杀手锏:Enter键不能用——这个总不能也跟硬盘坏联系上吧。可是对方又说他们也发现这个问题了,因为boot的时候没法按Enter键进入子菜单。可是在把硬盘移除之后,Enter键就能使用。这我就没解了,而且对方也保证了,要是最后换了硬盘之后,Enter键也没用就是他们的责任。这个时候,只能暂时承认是硬盘坏了,等着他们报价维修了。

硬盘损坏,换硬盘,320G的400,500G的500,这个价格一出,我就感觉事情开始超出自己能够掌控的范围了,开始不淡定了。可是后面,最最无奈的一个破财点出来了——数据恢复。据他们的说法是:硬盘磁道坏了,一般的方式无法通过数据线连接到机器上识别硬盘,然后用软件做数据恢复,而是在一个无尘的环境里面,拆开硬盘,把坏的硬盘上面磁盘的内容查找对应分区和文件夹复制到一个新的硬盘里面。这样做的手续费是600,然后推荐换个500G的硬盘(这个也是我想的,因为320G的的确有点小).加起来总共的费用1100.

这个时候,我已经开始有点想崩溃了,一杯水==>1100大洋,这样的一个因果实在是太超出意料。如果不做数据恢复的话,价格倒是便宜,可是电脑里面的确有很多对我来说很重要的数据,一些公司的进行了很久的项目,一些自己平时的技术积累,还有收集了放在桌面上一个妹子发给我的很多文件。这些在我心里的价格是很珍贵的,所以我不得不痛苦的承认,我得挨宰!

回公司找同事准备借个1200,路上维修点的人又打来电话说可以用一种克隆的方式,把硬盘里面的数据都拷贝到另外一个硬盘上面,然后价格是800.因为是在电话里面,一时说不清,我就跟对方说等我过去再说,可是让同事取钱的时候,还是让他取了1500,已经预测到这笔另加的钱应该是避免不了了。

再回到维修点,对方说用一个跟坏的磁盘一模一样大小的磁盘,在无尘的环境(又是无尘,无尘你妹啊)里把坏的磁盘的数据完全的拷贝到新磁盘上面。这样的做法一来恢复的数据很多,不用考虑专门恢复哪个文件夹里面的数据了,二来时间上也很快速(因为手上接了个任务,已经承诺了要明后两天完成,所以要求他们尽量快的修复电脑)。看起来这方法的确很好,可是价格不便宜(800),而且有个缺点,C盘里面的东西没法被恢复。这就意味着我桌面,我的文档,等很多地方的文件没法恢复了,特别是那个妹子发的那些文件…可是从时间和恢复的数据量上面来看,这又是唯一解。

最终的结果是,我倒了一杯水在键盘上,给了别人1200块钱,换了个除C盘没了和F,G,H变成E,F,G的新的320G的磁盘,64位的win8变成64位的win7.仅此而已,一切都和原先一样…..

回了公司,来不及哀悼,开始了悲催的加班节奏….

最重要的总结

数据的重要性

在维修的时候,和维修人员扯淡的时候,他的一句话让我很有感触:硬盘有价,数据无价,的确是这样,电脑上面任何一个部件坏了,换个一样或者更优的部件就能正常工作甚至比之前工作的更好。可是数据一旦没有了就真心没有了,不管那个是你心仪女子的照片,是你苦苦收集的一张张桌面背景,一首首高品质的好歌或者一部部的经典影片,也不管那个是你辛苦工作几个月甚至几年的论文或者程序。失去了就是失去了。所以要注意数据的备份

如何进行数据备份

作为一个到最后花了这么多钱做数据恢复的我,说这个话题也许有点不着调,但是我的确在这个方面有着一定的经验,只是之前是明白如何做却没有认识到这样做的重要性,最后就因为麻烦放弃了坚持。

数据的备份要考虑到下面几个问题:

  • 备份的频率
  • 备份的便捷性
  • 备份点的安全性
  • 备份点的稳定性

常见的备份方法就我所知有两种:本地备份(比如移动硬盘),云备份(各种网盘,Dropbox,Google Drive,金山快盘,百度云盘,115网盘)

本地备份:这个备份点的安全性和稳定性,只要买个好的移动硬盘(此处以移动硬盘代表本地备份的备份点),平时注意一下移动硬盘的放置地点,设置好强度足够的密码就能保证。但是如果数据是那种更新比较频繁的,通过本地备份,每次手动的拷贝的话,那么频率和便捷性就是一个相斥的方向了。所以本地备份适合那些变动比较少的,比如一些好的电影,有纪念意义的照片等数据

云备份:有过相关经验的人都知道,只要开着个软件,就能很实时的将你的增删改的文件保存到云服务器上,便捷性和频率上都无可挑剔,只是如果数据量比较大,可能软件会占用电脑一定的内存和cpu(我当初就是因为这个原因没能坚持一直实时开着软件备份)。在稳定性方面,因为好的云盘都是有多个分布在各地的服务器保存着多份数据的备份。哪怕有一台服务器挂了也不影响数据的完整性。所以稳定性上面可以有保障。但是在安全性方面,安全指的是数据不被他包括云盘服务提供商自身)窃取或查看,这一点,就没法保证。因为数据在别人那儿,你没法监督他的操作。建议的方式是国内和国外的云盘服务交叉使用。国外的公司还是有一些素质的,所以一些重要的,机密程度不是很高的文件,比如公司的一些开发中的项目可以考虑使用国外的云盘。只要你的公司不是国内的顶级公司,那么你的文件就算真的被对方查看了,也没法带给对方什么商业价值。至于其他的一些个人的非私密的摄影摄像文件,自己写的小程序等等就可以放心的放在同步速度比较快而且可以方便的分享给不能翻墙的国内朋友的国内网盘。

对于那些公司的机密文件,特别是后台的一些文件,任何移动硬盘或者云盘都是不靠谱的,应该的做法是每个公司自己建立好一个svn或者git服务器,而作为使用者的我们,应该多svn up和git commit。保证自己的文件尽量及时的同步到服务器上面。

好了,以上就是本人的一些比较罗嗦的经验了。(完)

又废了一个周末

  • 计划好的前端文档
  • 熬夜写好的chrome插件开发计划
  • 说好的翻译项目

好吧,如题,又废了一个周末,什么事都没干,唯一的安慰奖就是看了点jQuery Mobile,可是暂时还没制定app开发的计划,估计回头还得重新看一遍

已经轮回了多少个这样的周末了,死宅,熬夜,饿肚子,蒙头大睡,狂看小说

多少次的满满计划,多少次的雄心壮志,就这样在两天里埋葬,只留下写满懊悔的墓志铭


很担心啊,感觉自己在一步一步的变成那种自己十分讨厌的人。懒散,狭隘,目光短浅,斤斤计较。再这样死宅和颓废下去,后果估计真的会是这样,尼玛,真心烦躁

真心希望有个人在身边,至少不那么寂寞,至少能静下心来。

可是,这样把希望寄托在另外一个人身上,说到底也是对对方的不公平和对自己的逃避。

还是自己努力吧,骚年,人生如果只是一周又一周的轮回,到最后真的会痛哭流涕