-->

Creating a thread-safe temporary file name

2019-03-17 06:10发布

问题:

When using Tempfile Ruby is creating a file with a thread-safe and inter-process-safe name. I only need a file name in that way.

I was wondering if there is a more straight forward approach way than:

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

回答1:

Digging in tempfile.rb you'll notice that Tempfile includes Dir::Tmpname. Inside you'll find make_tmpname which does what you ask for.

Dir::Tmpname.make_tmpname "/tmp/źdźbło", nil
# => "/tmp/źdźbło20121209-1867-1qyptqe"
Dir::Tmpname.make_tmpname(['a', '.png'], nil)
# => "a20121209-2710-wcjbzr.png"

In the same file, there's also Dir::Tmpname.create which, depending on what you want to achieve, does a little more than make_tmpname. In particular, it figures out what temporary directory to use (assuming you're not on *nix where /tmp is a globally correct assumption). Still, a little ugly to use given that it expects a block:

Dir::Tmpname.create(['a', '.png']) { }
# => "/tmp/a20140224-15930-l9sc6n.png"

The block is there for code to test if the file exists and raise an Errno::EEXIST so that a new name can be generated with incrementing value tagged on the end.



回答2:

Since you only need the filename, what about using the SecureRandom for that:

require 'securerandom'

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

You can also use SecureRandom.alphanumeric



回答3:

I found the Dir:Tmpname solution did not work for me. When evaluating this:

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

Under MRI Ruby 1.9.3p194 I get:

uninitialized constant Dir::Tmpname (NameError)

Under JRuby 1.7.5 (1.9.3p393) I get:

NameError: uninitialized constant Dir::Tmpname

You might try something like this:

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