英文:
How to delete generated zip file after user finish download?
问题
我正在使用beego开发一个网站。
我生成了一个zip文件,让用户从我的网站上下载。然而,我不知道何时删除该文件。有没有办法让我知道用户是否已经完成了zip文件的下载,这样我就可以从磁盘上删除它?
或者,我可以实时生成zip文件并将*zip.File传递给net/http吗?我看到http.ServeFile()
接受一个ReadSeeker,但是根据文档,我认为zip.File不满足ReadSeeker接口。
在我的情况下,有没有一个好的方法来删除文件?
英文:
I'm developing a website using beego
I'm having a zip file generated to let user download from my website. However,I don't know when to delete the file. Is there a way for me to know if user have finished download the zip file, so I could delete it from disk?
Or, Can I generate zip file on-the-fly and past the *zip.File to net/http?
I see http.ServeFile()
accept a ReadSeeker, yet I think zip.File don't satisfy ReadSeeker
interface according to the doc.
Is there a good way to do file delete on my situation?
答案1
得分: 2
导入 os
并运行以下代码:
os.Remove(filename)
编辑:我能想到的唯一方法是使用一个 ajax 库从 API 下载文件,然后在完成后调用另一个 API。普通的 ajax 调用在这里不起作用,因为所有浏览器都不允许 ajax 直接访问磁盘,所以唯一的方法是使用像这个库一样的库:http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/
该库的 API 可以利用以下方式的成功和失败回调:
$.fileDownload('/url/to/download.pdf', {
successCallback: function (url) {
// 进行另一个 ajax 调用来删除文件...
},
failCallback: function (html, url) {
// 处理失败...
}
});
英文:
Import "os"
and run the following line:
os.Remove(filename)
Edit: The only way I could see this happening is by using an ajax library to download the files from an api then call a different api on finish. Normal ajax calls wont work here as all browsers wont allow ajax to access the disk directly, so the only way to do this is by using a library like this one http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/
The library api can leverage things like success and failure callbacks in the following way:
$.fileDownload('/url/to/download.pdf', {
successCallback: function (url) {
//do another ajax call to delete the file...
},
failCallback: function (html, url) {
//handle failure...
}
});
答案2
得分: 2
你需要在请求处理程序中的某个地方使用defer os.Remove(zf)
。用户下载文件与任何其他请求没有区别:当请求处理程序执行完毕时,你就知道已经完成了。
这样做仍然会在磁盘上留下偶尔的压缩文件(例如,如果服务器崩溃、重启或被中断),所以你需要定期运行一个cron作业或类似的任务来删除旧文件。
如果你可以始终重新生成压缩文件(这将要求你的底层数据要么不变,要么有版本控制),则可以动态生成zip文件,使用http.ServeContent
。你可以编写自己的Seek
函数,它在zip上始终重置zip流并跳过n个字节。如果有大量的寻址操作,这种方法效率会非常低下,但你可以拒绝接受范围请求,这样就只会有两次寻址操作:一次到文件末尾,一次回到开头(用于计算长度)。
另一种避免使用磁盘文件的简单方法是在内存中生成zip文件,然后使用strings.Reader
通过http.ServeContent
进行传输。但是,使用这种方法在服务器中管理内存使用可能会比较困难。
英文:
You need to defer os.Remove(zf)
somewhere in your request handler. A user downloading a file is no different from any other request: you know you're done when the request handler has finished executing.
This will still leave the occasional zip file on disk (for example, if your server crashes, restarts, or is otherwise interrupted), so you'll need a cron job or similar to run periodically to remove old files.
It's possible to generate a zipfile on the fly, using http.ServeContent, if you can regenerate the zipfile consistently (which will require, for example, that your underlying data is either unchanging or versioned). You can do this by writing your own Seek
on top of zip that always resets the zip stream and skips ahead n bytes. This would be horrendously inefficient if there was a lot of seeking, but you can refuse to accept ranges and then there'll be exactly two seeks: one to the end of the file and one back to the start (done to compute the length).
Another simple way to avoid disk files is to generate the zip file in memory, and then use a strings.Reader to serve it via http.ServeContent. It'll be hard to manage memory use in your server with this solution though.
答案3
得分: 2
根据@Paul Hankin的建议,我只是添加了代码。
返回中间件.ResponderFunc(func(w http.ResponseWriter, r runtime.Producer) {
fn := filepath.Base(filePath)
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", fn))
io.Copy(w, file)
defer os.Remove(filePath) // 下载的文件路径。
file.Close()
})
英文:
Like @Paul Hankin suggested , I am just adding code.
return middleware.ResponderFunc(func(w http.ResponseWriter, r runtime.Producer) {
fn := filepath.Base(filePath)
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", fn))
io.Copy(w, file)
defer os.Remove(filePath) // Path to file you've downloaded.
file.Close()
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论