如果我通过
Tempfile
创建了一个临时文件,除了将其复制到另一个文件之外,还有什么方法可以使其“永久”吗?我想避免当关联的 Tempfile
实例被垃圾收集或进程终止时它被删除。
在相关点上,有没有办法利用
Tempfile
机制(或使用类似的机制)来获取“新”文件名,而不必以该名称创建文件?
其实不然。对于问题本身,请参阅:
ObjectSpace.undefine_finalizer(tmpfile)
Tempfile 库使用 Ruby ObjectSpace 终结器在垃圾回收时自动删除自身。通过使用上面的行,如果您不删除临时文件,您可以删除它自身的能力。因此,例如:
$ irb
2.0.0p0 :001 > require "tempfile"
=> true
2.0.0p0 :002 > t = Tempfile.new("test")
=> #<Tempfile:/tmp/test20140122-6655-80p4b7>
2.0.0p0 :003 > t.write("Hi!")
=> 3
2.0.0p0 :004 > ObjectSpace.undefine_finalizer(t)
=> #<Tempfile:/tmp/test20140122-6655-80p4b7>
2.0.0p0 :005 > exit
$ cat /tmp/test20140122-6655-80p4b7
Hi!
$
还有一些事情需要注意。 Tempfile 将使用系统临时文件目录,例如
/tmp
,操作系统每隔一段时间就会自动清理一次(例如 每次启动时)。因此,即使您“保留”该文件,您也需要接受它的消失,或者将其移动到默认情况下不会被清除的目录,例如 /var/tmp
(用于持久临时文件的 Linux 目录)文件)。
至于你的第二个问题,请尝试here中的代码:
Dir::Tmpname.create('your_application_prefix') { |path| puts path }
它需要一个
require "tmpdir"
。
我认为最简单的解决方案可能是对
Tmpfile
类进行猴子修补以添加 persist
方法。此方法采用临时文件将移动到的文件名。此外,它删除了终结器,以便临时文件在退出时不会被删除。
require 'tempfile'
require 'fileutils'
class Tempfile
def persist(filename)
FileUtils.mv(self.path, filename)
ObjectSpace.undefine_finalizer(self)
end
end
file = Tempfile.new('tmp')
file.write('hello world')
file.close
file.persist('hello.txt')
运行此程序将通过移动原始临时文件而不是复制它来创建持久文件
./hello.txt
。
就我而言,我尝试使用
ObjectSpace.undefine_finalizer(t)
,但它对我来说失败了(我认为可能是由于垃圾收集器在请求完成后,只是从 tmp 文件夹中获取所有内容)。所以我只是做了一些简单有效的事情,将其移到 tmp 文件夹之外
t = Tempfile.new("test")
# Extra validation, check if new path is empty & clear it
FileUtils.rm(new_path) if File.file?(new_path)
# Persisting the file
FileUtils.mv(t.path, new_path)
一切顺利! 👍🏼(如果您检查该新文件夹,该文件应该永远存在)
记得稍后清理它,可能就像我在预验证中所做的那样