我正在开发一个批量文件上传器。多个文件通过单独的请求上传,我的用户界面提供上传进度和成功/失败信息。然后,在所有文件完成后,会有一个最终请求来处理/完成它们。为了实现这一点,我需要创建许多临时文件,这些文件的生命周期超过了单个请求。当然,我还需要确保文件名在应用程序实例之间是唯一的。
通常,我会使用Tempfile
来获得易于理解的唯一文件名,但在这种情况下,由于文件需要保留直到另一个请求进来进一步处理它们,所以这种方法行不通。当文件被关闭并进行垃圾回收时,Tempfile
会自动取消链接这些文件。
早期的一个问题这里建议使用 Dir::Tmpname.make_tmpname
,但是这似乎没有文档记录,并且我不知道它是否线程/多进程安全。它能够保证吗?
在C语言中,我将打开文件O_EXCL
,如果文件已经存在,这将失败。然后我可以不断重试,直到成功获得一个具有真正唯一名称的文件句柄。但是Ruby的File.open
似乎没有任何“独占”选项。如果我要打开的文件已经存在,我必须将它附加到末尾、以写入方式打开或清空它。
在Ruby中是否有正确的方法来完成这个任务?
我已经想出了一个方法,我认为是安全的,但是它似乎过于复杂:
# make a unique filename
time = Time.now
filename = "#{time.to_i}-#{sprintf('%06d', time.usec)}"
# make tempfiles (this is gauranteed to find a unique creatable name)
data_file = Tempfile.new(["upload", ".data"], UPLOAD_BASE)
# but the file will be deleted automatically, which we don't want, so now link it in a stable location
count = 1
loop do
begin
# File.link will raise an exception if the destination path exists
File.link(data_file.path, File.join(UPLOAD_BASE, "#{filename}-#{count}.data"))
# so here we know we created a file successfully and nobody else will take it
break
rescue Errno::EEXIST
count += 1
end
end
# now unlink the original tempfiles (they're still writeable until they're closed)
data_file.unlink
# ... write to data_file and close it ...
注意:此方法不适用于 Windows 系统。对我来说没问题,但读者要注意。
在我的测试中,这个方法的可靠性很高。但是,是否有更加简单明了的方法呢?