37

当使用TempfileRuby 创建一个具有线程安全和进程间安全名称的文件时。这样我只需要一个文件名。

我想知道是否有比以下更直接的方法:

t = Tempfile.new(['fleischwurst', '.png'])
temp_path = t.path
t.close
t.unlink
4

4 回答 4

62

目录::Tmpname.create

你可以使用Dir::Tmpname.create. 它计算出要使用的临时目录(除非您将目录传递给它)。考虑到它需要一个块,使用起来有点难看:

require 'tmpdir'
# => true
Dir::Tmpname.create(['prefix-', '.ext']) {}
# => "/tmp/prefix-20190827-1-87n9iu.ext"
Dir::Tmpname.create(['prefix-', '.ext'], '/my/custom/directory') {}
# => "/my/custom/directory/prefix-20190827-1-11x2u0h.ext"

该块用于测试文件是否存在并引发代码,Errno::EEXIST以便可以生成一个新名称,并在末尾附加递增值。

Rails 解决方案

Ruby on Rails实现的解决方案很简短,与最初在 Ruby 中实现的解决方案相似:

require 'tmpdir'
# => true
File.join(Dir.tmpdir, "YOUR_PREFIX-#{Time.now.strftime("%Y%m%d")}-#{$$}-#{rand(0x100000000).to_s(36)}-YOUR_SUFFIX")
=> "/tmp/YOUR_PREFIX-20190827-1-wyouwg-YOUR_SUFFIX"
File.join(Dir.tmpdir, "YOUR_PREFIX-#{Time.now.strftime("%Y%m%d")}-#{$$}-#{rand(0x100000000).to_s(36)}-YOUR_SUFFIX")
=> "/tmp/YOUR_PREFIX-20190827-1-140far-YOUR_SUFFIX"

Dir::Tmpname.make_tmpname(Ruby 2.5.0 及更早版本)

Dir::Tmpname.make_tmpname 在 Ruby 2.5.0 中被移除。在 Ruby 2.4.4 之前,它可以接受目录路径作为前缀,但从 Ruby 2.4.4 开始,目录分隔符被删除。

深入研究tempfile.rb你会发现Tempfile其中包括Dir::Tmpname. 在里面你会发现make_tmpname哪个可以满足你的要求。

require 'tmpdir'
# => true
File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname("prefix-", nil))
# => "/tmp/prefix-20190827-1-dfhvld"
File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(["prefix-", ".ext"], nil))
# => "/tmp/prefix-20190827-1-19zjck1.ext"
File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(["prefix-", ".ext"], "suffix"))
# => "/tmp/prefix-20190827-1-f5ipo7-suffix.ext"
于 2012-12-09T13:35:52.440 回答
3

由于在 Ruby 2.5.0 中Dir::Tmpname.make_tmpname被删除,这个回退到使用:SecureRandom

require "tmpdir"

def generate_temp_filename(ext=".png")
  filename = begin
    Dir::Tmpname.make_tmpname(["x", ext], nil)
  rescue NoMethodError
    require "securerandom"
    "#{SecureRandom.urlsafe_base64}#{ext}"
  end
  File.join(Dir.tmpdir, filename)
end
于 2019-05-27T18:02:17.363 回答
1

由于您只需要文件名,因此使用SecureRandom怎么样:

require 'securerandom'

filename =  "#{SecureRandom.hex(6)}.png" #=> "0f04dd94addf.png"

你也可以使用SecureRandom.alphanumeric

于 2018-07-16T23:00:18.290 回答
-2

我发现 Dir:Tmpname 解决方案对我不起作用。在评估这个时:

Dir::Tmpname.make_tmpname "/tmp/blob", nil

在 MRI Ruby 1.9.3p194 下,我得到:

uninitialized constant Dir::Tmpname (NameError)

在 JRuby 1.7.5 (1.9.3p393) 下,我得到:

NameError: uninitialized constant Dir::Tmpname

你可以尝试这样的事情:

def temp_name(file_name='', ext='', dir=nil)
    id   = Thread.current.hash * Time.now.to_i % 2**32
    name = "%s%d.%s" % [file_name, id, ext]
    dir ? File.join(dir, name) : name
end
于 2014-02-25T21:43:21.647 回答