我需要在服务器上创建一个文件,将其提供给客户端,之后我宁愿从服务器中删除该文件。
以下是我正在尝试的内容:
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世界,所以我有点迷失方向,并且有任何其他改善上述建议的建议值得赞赏。
答案 0 :(得分:2)
1)您可以将文件移动到临时文件夹并删除所有超过0.5小时的文件
2)你可以尝试
result = serve_fileobj(RETURN_FILE,disposition='attachment',
content_type='.txt',name=filename)
os.unlink(filename)
return result
3)尝试使用StringIO文件对象,它可以将字符串包装成文件。
答案 1 :(得分: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 :(得分: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)