下载大文件 - 使用grails的应用程序

时间:2011-05-25 19:13:09

标签: sql json grails csv

我正在开发一个RESTful Web服务,允许用户下载从数据库中动态检索的csv和json格式的数据。

现在我正在使用StringWriter写出CSV数据。我主要担心的是结果集可能会变得非常大,具体取决于用户输入。在这种情况下,将它们全部留在记忆中对我来说似乎不是一个好主意。

我正在考虑创建一个临时文件,但是如何确保在下载完成后很快删除该文件。

有没有更好的方法来做到这一点。

感谢您的帮助。

4 个答案:

答案 0 :(得分:1)

如果内存是问题,您可以简单地写出直接写入输出流的响应编写器?这样你就不会在内存中存储任何东西,也不需要写出临时文件:

// controller action for CSV download
def download = {
    response.setContentType("text/csv")
    response.setHeader("Content-disposition", "attachment;filename=downloadFile.csv")
    def results = // get all your results
    results.each { result ->
        out << result.col1 << ',' << result.col2 // etc
        out << '\n'
    }
}

这会向输出流写出,因为它会循环结果。

理论上你可以通过使用可滚动的结果集来实现更高的内存效率 - 请参阅Querying with GORM - Criteria的“使用可滚动结果”部分 - 并在写出响应编写器时循环。从理论上讲,这意味着您也没有将所有数据库结果加载到内存中,但实际上,如果您使用的是MySQL(及其Java连接器),这可能无法正常工作。手动批处理查询也可能有效(获取DB行1-10000,写出,获取10001-20001等)

使用JSON可能会更加困难,具体取决于您用于渲染对象的库。

答案 1 :(得分:0)

嗯,防止临时文件长时间停留的最简单的解决方案是一个cron作业,只删除临时目录中修改时间比1小时更早的任何文件。

如果您希望在Grails中完成所有操作,则可以设计Quartz作业来清理文件。此作业可以如上所述(并且只需检查修改时间戳以决定要删除的内容),或者只能“按需”运行作业,并使用要删除的文件名参数。调用下载操作后,您可以在X分钟后安排清理该特定文件(以便有足够的时间成功下载)。然后,该工作将负责简单地删除该文件。

答案 2 :(得分:0)

要创建在会话过期后自动删除的临时文件,您可以使用Session Temp Files plugin

答案 3 :(得分:0)

根据所涉及的文件数量,您始终可以使用http://download.oracle.com/javase/1,5.0/docs/api/java/io/File.html#deleteOnExit()来确保在VM关闭时文件被烧掉。