前情
最近在做活动编辑器的时候,考虑到运营人员很多都没有图片上传的权限,所以想在活动编辑器里面内置一个这样的功能,让运营可以使用上传控件或者托拽的方式上传图片到服务器,并在上传成功之后,自动把地址放到文本框里。
第一步要做的就是尝试着实现用FTP来上传一个文件到服务器的指定目录,同时基于文件的sha1值来命名上传之后的文件。
手上现有的两种实现路径是NodeJs和Python,不过想到最近刚学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()
参考文档
- Python Script Uploading files via FTP
- Extracting extension from filename in Python
- Why can’t I call read() twice on an open file?
- 我是如何 Python 一句话校验软件哈希值的