Подтвердить что ты не робот

Создание безопасного временного имени файла

При использовании Tempfile Ruby создает файл с безопасным потоком и межпроцессорным именем. Мне нужно только имя файла.

Мне было интересно, есть ли более прямой подход, чем:

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

Ответ 1

Dir :: 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"

Ответ 2

Так как Dir::Tmpname.make_tmpname был удален в Ruby 2.5.0, он возвращается к использованию 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

Ответ 3

Поскольку вам нужно только имя файла, как насчет использования SecureRandom для этого:

require 'securerandom'

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

Вы также можете использовать SecureRandom.alphanumeric

Ответ 4

Я нашел, что решение 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