如何使用cherrypy提供文件并从服务器删除文件?
我需要在服务器上创建一个文件,然后把它提供给客户端,最后我希望能把这个文件从服务器上删除。
这是我现在正在尝试的:
def myaction():
fs = facts.generatefacts(int(low),int(high),int(amount),op)
filename = 'test.txt'
FILE = open(filename,'w')
FILE.writelines('my\nstuff\nhere')
FILE.close()
RETURN_FILE = open(filename,'r')
return serve_fileobj(RETURN_FILE,disposition='attachment',
content_type='.txt',name=filename)
myaction.exposed = True
关于这个过程,有几个地方我不太满意。比如,我不明白为什么我需要打开文件两次。我本以为可以直接把内容写入响应对象,而不需要先创建一个文件对象,但这不是我今天要问的问题。
上面的代码实现了我想要的效果,但留下了一个文件。如果我在返回响应之前就删除了这个文件,那么(当然)就找不到这个文件了。
有没有办法在文件被提供后立刻把它删除掉?
我之前是做Java的,所以现在有点不适应,任何其他改进建议也非常欢迎。
3 个回答
0
这个对我有效:
class Handler:
...
def download_complete(self)
os.unlink(cherrypy.request.zipFileName)
def download(self, path)
zipFileName = createZip(path)
cherrypy.request.zipFileName = zipFileName
cherrypy.request.hooks.attach('on_end_request', self.download_complete)
return cherrypy.lib.static.serve_download(zipFileName)
1
下面的解决方案使用弱引用来清理临时文件(在这个例子中也包括临时目录),一旦文件通过cherrypy完全发送完毕,就会进行清理。
我使用了临时目录,因为这样可以处理那些在发送最终结果之前可能会创建多个文件的过程(比如,返回一个压缩的Excel文件)。不过,对于简单的情况,只用一个临时文件就足够了。
import cherrypy
from cherrypy import expose
import zipfile
import weakref
import shutil
import os
import tempfile
PARENT_TEMP_DATA_DIR = '/tmp/cherrypy_data_files'
def single_file_zip(filepath):
'Give a filepath, creates a zip archive in the same directory, with just the single file inside'
filename = os.path.basename(filepath)
zipname = '%s.zip' % os.path.splitext(filename)[0]
if filename.lower() == zipname.lower():
raise ValueError("Can't use .zip file as source")
zippath = os.path.join(os.path.dirname(filepath), zipname)
zf = zipfile.ZipFile(zippath, mode='w', compression=zipfile.ZIP_DEFLATED)
zf.write(filepath, filename)
zf.close()
return zippath
class DataFiles(object):
def __init__(self):
self.weak_references = {}
def cleanup(self, wr):
if wr in self.weak_references:
filepath = self.weak_references[wr]
if os.path.isfile(filepath):
try:
os.remove(filepath)
except Exception:
pass
if os.path.isdir(filepath):
shutil.rmtree(filepath, ignore_errors=True)
self.weak_references.pop(wr)
@expose
def index(self):
tempdir = os.path.abspath(tempfile.mkdtemp(dir=PARENT_TEMP_DATA_DIR))
txt_path = os.path.join(tempdir, 'my_data.txt')
with open(txt_path, 'wb') as fh:
fh.write('lots of data here\n')
zip_path = single_file_zip(txt_path)
os.remove(txt_path) # not strictly needed, as the cleanup routine would remove this anyway
result = cherrypy.lib.static.serve_download(zip_path)
# the weak-reference allows automatic cleanup of the temp dir once the file is served
wr = weakref.ref(result, self.cleanup)
self.weak_references[wr] = tempdir
return result
if __name__=='__main__':
# on startup clean up any prior temporary data
tempdir_parent = PARENT_TEMP_DATA_DIR
print 'Clearing %s' % tempdir_parent
if not os.path.exists(tempdir_parent):
os.mkdir(tempdir_parent)
for filename in os.listdir(tempdir_parent):
filepath = os.path.join(tempdir_parent, filename)
if os.path.isfile(filepath):
print 'Deleting file %s' % filepath
os.remove(filepath)
if os.path.isdir(filepath):
print 'Removing directory %s and all contents' % filepath
shutil.rmtree(filepath, ignore_errors=True)
# start CherryPy
cherrypy.quickstart(DataFiles())
2
1) 你可以把文件移动到一个临时文件夹里,然后删除所有超过半小时的旧文件。
2) 你可以试试这个方法。
result = serve_fileobj(RETURN_FILE,disposition='attachment',
content_type='.txt',name=filename)
os.unlink(filename)
return result
3) 试着使用 StringIO 这个文件对象,它可以把字符串包装起来,让它看起来像一个文件。