您的位置:首页 > 编程语言 > Python开发

python 实现文件上传下载

2016-08-08 00:00 375 查看
介绍

实现支持文件上传、下载、删除的api接口(支持多文件上传)

使用mongo 做为后端存储

支持异步

一.使用python tornado实现

python 版本 2.7

tornado版本 4.3

# -*- coding: utf-8 -*-
__Author__ = 'Traveler'

import json
import datetime

import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.gen
#
from tornado.concurrent import run_on_executor
from werkzeug import secure_filename
from concurrent import futures
#
import pymongo
import gridfs
from bson.objectid import ObjectId
from cStringIO import StringIO

import logging
# import logging.handlers
logging.basicConfig(level=logging.INFO,format='%(asctime)s %(filename)s %(module)s %(funcName)s %(process)d %(thread)d %(threadName)s [line:%(lineno)d] [%(levelname)s] %(message)s')

log = logging.getLogger()

# 定义 storage Handler
class StorageFiles(tornado.web.RequestHandler):
def initialize(self):
self.mongo = pymongo.MongoClient('127.0.0.1', 27017)
self.db = self.mongo['storage']
self.fs = gridfs.GridFS(self.db, 'files')
self.executor = futures.ThreadPoolExecutor(max_workers=24)
#
def Time(self):
date1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
date2 = datetime.datetime.now().strftime('.%f')[:4]
date = date1 + date2
return date
# 只允许上传下列后缀的文件
def __allowed_file(self, filename):
ALLOWED_EXTENSIONS = set(['txt', 'conf', 'ini', 'cf', 'yml', 'xml', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'json', 'gz', 'rar', 'unzip','tgz'])
return '.' in filename and filename.split('.', 1)[1] in ALLOWED_EXTENSIONS
#
@tornado.web.asynchronous
@tornado.gen.coroutine
def get(self):
yield self._get()

@run_on_executor
def _get(self):
filename = self.get_argument('filename')
files_id = self.get_argument('files_id')
#
files = self.fs.get(ObjectId(files_id))
data = files.read()
#
self.set_header('Content-Type', 'application/octet-stream;charset=utf-8')
self.set_header('Content-Disposition', 'attachment; filename=' + filename)
self.write(data)

#
@tornado.web.asynchronous
@tornado.gen.coroutine
def post(self):
yield self._post()

@run_on_executor
def _post(self):
begin_time = self.Time()
#
files_meta = self.request.files['files']
#
uri = []
for meta in files_meta:
if meta and self.__allowed_file(meta['filename']):
filename = secure_filename(meta['filename'])  # 获取一个安全的文件名,仅支持ASAII字符,如果需要文件包含中文,可注释此行代码
# files_meta.save(os.path.join(self._upload_folder,filename))
data = StringIO(meta['body']).getvalue()
files_id = self.fs.put(data=data, filename=filename)
args = '?filename=%s&files_id=%s' % (filename, files_id)
uri.append(self.reverse_url(name='StorageFiles') + args)
else:
self.write(json.dumps({'error': 'The format is not correct'}))
#
runtime = {'begin_time': begin_time, 'end_time': self.Time()}
res = {}
res['status'] = 'ok'
res['runtime'] = runtime
# res['uri'] = {'download': download, 'delete': delete}
res['uri'] = uri
#
self.write(json.dumps(res,sort_keys=True,indent=4,separators=(',',':')))

#
@tornado.web.asynchronous
@tornado.gen.coroutine
def delete(self):
yield self._delete()

@run_on_executor
def _delete(self):
begin_time = self.Time()
files_id = self.get_argument('files_id')
self.fs.delete(ObjectId(files_id))
# os.remove(self._upload_folder + '/' + filename)
runtime = {'begin_time': begin_time, 'end_time': self.Time()}
res = {}
res['status'] = 'ok'
res['runtime'] = runtime
self.write(json.dumps(res,sort_keys=True,indent=4,separators=(',',':')))

#
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r'/storage',StorageFiles,{},'StorageFiles')
]
#
settings = {
'debug': True,
}
#
super(Application,self).__init__(handlers=handlers,**settings)
#
def run():
import tornado.options
from tornado.options import define, options
define('port', default=8000, help='run on the given port', type=int)
tornado.options.parse_command_line()
app = Application()
# app.listen(options.port,address='0.0.0.0')
tornado.httpserver.HTTPServer(app).listen(options.port)
log.info('listen http://127.0.0.1:8000') tornado.ioloop.IOLoop.instance().start()

if __name__ == '__main__':
run()

二.使用python flask实现

python 版本 2.7

flask 版本0.10.1

Flask-RESTful 版本 (0.3.5)

ps: 其实flask-restful 的工作模式与tornado比较接近了.

# -*- coding: utf-8 -*-
#
from flask import Flask
from flask import jsonify
from flask import request
from flask import make_response
from werkzeug import secure_filename
#
from flask.ext.restful import Api
from flask.ext.restful import Resource
from flask.ext.restful import fields
#
import datetime
#
import pymongo
from bson.objectid import ObjectId
import gridfs
from cStringIO import StringIO

#
class StorageFiles(Resource):
def __init__(self):
super(StorageFiles, self).__init__()
# self._upload_folder = '/tmp/storage'
self.mongo = pymongo.MongoClient('127.0.0.1',27017)
self.db = self.mongo['storage']
self.fs = gridfs.GridFS(self.db,'files')

def Time(self):
date1 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
date2 = datetime.datetime.now().strftime('.%f')[:4]
date = date1 + date2
return date

#
def __allowed_file(self,filename):
ALLOWED_EXTENSIONS = set(['txt', 'conf', 'ini', 'cf', 'yml', 'xml', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'json', 'gz', 'rar','unzip', 'tgz'])
return '.' in filename and filename.split('.',1)[1] in ALLOWED_EXTENSIONS
#
def get(self):
filename = request.values['filename']
files_id = request.values['files_id']
#
files = self.fs.get(ObjectId(files_id))
data = files.read()

headers = {}
headers['Content-Type'] = 'application/octet-stream; charset=utf-8'
headers['Content-Disposition'] = 'attachment; filename=' + filename

return make_response(data,200,headers)
#
def post(self):
begin_time = self.Time()
# files = request.files['files']
files_meta = request.files.getlist('files')
#
uri = []
for meta in files_meta:
filename = meta.filename
if filename and self.__allowed_file(filename):
filename = secure_filename(filename)
# files.save(os.path.join(self._upload_folder,filename))
data = StringIO(meta.read()).getvalue()
files_id = self.fs.put(data=data,filename=filename)
uri.append(fields.url_for(endpoint='StorageFiles',files_id=files_id,filename=filename))
else:
return make_response(jsonify({'error':'The format is not correct'}),403)
#
runtime = {'begin_time': begin_time, 'end_time': self.Time()}
res = {}
res['status'] = 'ok'
res['runtime'] = runtime
res['uri'] = uri
#
return make_response(jsonify(res),200)
#
def put(self):
pass
#
def delete(self):
begin_time = self.Time()
files_id = request.values['files_id']

self.fs.delete(ObjectId(files_id))
# os.remove(self._upload_folder + '/' + filename)
runtime = {'begin_time': begin_time, 'end_time': self.Time()}
res = {}
res['status'] = 'ok'
res['runtime'] = runtime
return make_response(jsonify(res), 200)
#
app = Flask(__name__)

api = Api(app=app)
api.add_resource(StorageFiles,'/storage',endpoint='StorageFiles')

#
if __name__ == '__main__':
app.run(port=8000,debug=True)

测试

文件:test.txt

上传:

curl -i -F 'files=@test.txt' http://127.0.0.1:8000/storage

下载:

curl 'http://127.0.0.1:8000/storage?filename=test.txt&files_id=57a856942f4dfd2f9923ba26'

删除:

curl -X DELETE 'http://127.0.0.1:8000/storage?filename=test.txt&files_id=57a856942f4dfd2f9923ba26'

备注: 下载和删除的url改成上传后返回的uri.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python Tornado Flask