如何使用cherrypy提供文件并从服务器中删除文件?

时间:2011-09-14 10:01:42

标签: python 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 :(得分: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)