如何通过send_file发送文件后删除Sinatra中的文件?

时间:2010-05-10 20:05:07

标签: ruby sinatra

我有一个简单的sinatra应用程序需要生成一个文件(通过外部进程),将该文件发送到浏览器,最后从文件系统中删除该文件。这些方面的东西:

class MyApp < Sinatra::Base
  get '/generate-file' do

    # calls out to an external process, 
    # and returns the path to the generated file
    file_path = generate_the_file()  

    # send the file to the browser
    send_file(file_path)

    # remove the generated file, so we don't
    # completely fill up the filesystem.
    File.delete(file_path)

    # File.delete is never called.

  end
end

然而,似乎send_file调用完成了请求,并且后面的任何代码都没有运行。

有没有办法确保生成的文件在成功发送到浏览器后被清除?或者我是否需要在某个时间间隔内使用运行清理脚本的cron作业?

4 个答案:

答案 0 :(得分:4)

不幸的是,使用send_file时没有任何回调。这里的常见解决方案是使用cron任务来清理临时文件

答案 1 :(得分:1)

您可以使用开始...确保块来清理文件:

file_path = generate_the_file()  
begin
  send_file(file_path)
ensure
  File.delete(file_path)
end

之所以有效,是因为在Sinatra内部。 #send_file调用#halt,然后#halt调用throw :halt。调用 throw 时,将取消堆栈堆栈,直到相应的 catch (位于Sinatra中的某个位置)为止,但是取消堆栈时,确保块运行。

答案 2 :(得分:1)

send_file 正在流式传输文件,它不是同步调用,因此您可能无法捕捉到它的结尾来清理文件。我建议将它用于静态文件或非常大的文件。对于大文件,您将需要一个 cron 作业或其他一些解决方案来稍后进行清理。您不能使用相同的方法执行此操作,因为当执行仍在 get 方法中时,send_file 不会终止。如果你真的不关心流媒体部分,你可以使用同步选项。

begin
   file_path = generate_the_file()  
   result File.read(file_path)
   #...
   result # This is the return
ensure
   File.delete(file_path) # This will be called..
end

当然,如果您对文件不感兴趣,您可以坚持使用 Jochem 的答案,该答案完全消除了开始-确保-结束。

答案 3 :(得分:0)

这可以是将文件内容临时存储在变量中的解决方案,例如:

  

contents = file.read

在此之后,删除文件:

  

File.delete(FILE_PATH)

最后,返回内容:

  

内容

这与您的send_file()具有相同的效果。