在 Ruby on Rails 中获取空临时目录的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1139265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:28:42  来源:igfitidea点击:

What is the best way to get an empty temporary directory in Ruby on Rails?

ruby-on-railsruby

提问by Mike

What is the best way to get a temporary directory with nothing in it using Ruby on Rails? I need the API to be cross-platform compatible. The stdlib tmpdirwon't work.

使用 Ruby on Rails 获取没有任何内容的临时目录的最佳方法是什么?我需要 API 是跨平台兼容的。stdlib tmpdir将不起作用。

采纳答案by slillibri

The Dir#tmpdirfunction in the Ruby core (not stdlib that you linked to) should be cross-platform.

Dir#tmpdirRuby 核心中的函数(不是您链接的 stdlib)应该是跨平台的。

To use this function you need to require 'tmpdir'.

要使用此功能,您需要require 'tmpdir'.

回答by Justin Tanner

The Dirobject has a method mktmpdirwhich creates a temporary directory:

Dir对象有一个方法mktmpdir创建一个临时目录:

require 'tmpdir' # Not needed if you are using rails.

Dir.mktmpdir do |dir|
  puts "My new temp dir: #{dir}"
end

The temporary directory will be removed after execution of the block.

块执行后临时目录将被删除。

回答by fguillen

A general aprox I'm using now:

我现在使用的一般 aprox:

def in_tmpdir
  path = File.expand_path "#{Dir.tmpdir}/#{Time.now.to_i}#{rand(1000)}/"
  FileUtils.mkdir_p path
  yield path
ensure
  FileUtils.rm_rf( path ) if File.exists?( path )
end

So in your code you can:

所以在你的代码中你可以:

in_tmpdir do |tmpdir|
  puts "My tmp dir: #{tmpdir}"
  # work with files in the dir
end

The temporary dir will be removedautomatically when your method will finish.

当您的方法完成时,临时目录自动删除

回答by ijcd

Ruby has Dir#mktmpdir, so just use that.

Ruby 有 Dir#mktmpdir,所以只需使用它。

require 'tempfile'
Dir.mktmpdir('prefix_unique_to_your_program') do |dir|
    ### your work here ###
end

See http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tmpdir/rdoc/Dir.html

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tmpdir/rdoc/Dir.html

Or build your own using Tempfile tempfile that is process and thread unique, so just use that to build a quick Tempdir.

或者使用进程和线程唯一的 Tempfile 临时文件构建您自己的临时文件,因此只需使用它来构建快速 Tempdir。

require 'tempfile'
Tempfile.open('prefix_unique_to_your_program') do |tmp|
  tmp_dir = tmp.path + "_dir"
  begin
    FileUtils.mkdir_p(tmp_dir)

    ### your work here ###
  ensure
    FileUtils.rm_rf(tmp_dir)
  end
end

See http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/Tempfile.htmlfor optional suffix/prefix options.

有关可选的后缀/前缀选项,请参阅http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/Tempfile.html

回答by fguillen

require 'tmpdir' # not needed if you are loading Rails
tmp_dir = File.join(Dir::tmpdir, "my_app_#{Time.now.to_i}_#{rand(100)}")
Dir.mkdir(tmp_dir)

Works for me.

对我来说有效。

回答by Dennis

You can use Dir.mktmpdir.

您可以使用Dir.mktmpdir.

Using a block will get rid of the temporary directory when it closes.

使用块将在关闭时摆脱临时目录。

Dir.mktmpdir do |dir|
  File.open("#{dir}/foo", 'w') { |f| f.write('foo') }
end

Or if you need multiple temp directories to exist at the same time, for example

或者,如果您需要同时存在多个临时目录,例如

context 'when there are duplicate tasks' do
  it 'raises an DuplicateTask error' do
    begin
      tmp_dir1 = Dir.mktmpdir('foo')
      tmp_dir2 = Dir.mktmpdir('bar')

      File.new("#{tmp_dir1}/task_name", 'w+')
      File.new("#{tmp_dir2}/task_name", 'w+')

      expect { subject.filepath('task_name') }.to raise_error(TaskFinder::DuplicateTask)
    ensure
      FileUtils.remove_entry tmp_dir1
      FileUtils.remove_entry tmp_dir2
    end
  end
end

Dir.mktmpdircreates a temporary directory under Dir.tmpdir(you'll need to require 'tmpdir'to see what that evaluates to).

Dir.mktmpdirDir.tmpdir(您需要require 'tmpdir'查看其评估结果)下创建一个临时目录。

If you want to use your own path, Dir.mktmpdirtakes an optional second argument tmpdirif non-nil value is given. E.g.

如果您想使用自己的路径,如果给出非 nil 值,Dir.mktmpdir则采用可选的第二个参数tmpdir。例如

Dir.mktmpdir(nil, "/var/tmp") { |dir| "dir is '/var/tmp/d...'" }

回答by AlexChaffee

Update: gem install files, then

更新:gem install files,然后

require "files"
dir = Files do
  file "hello.txt", "stuff"
end

See below for more examples.

有关更多示例,请参见下文。



Here's another solution, inspired by a few other answers. This one is suitable for inclusion in a test (e.g. rspec or spec_helper.rb). It makes a temporary dir based on the name of the including file, stores it in an instance variable so it persists for the duration of the test (but is not shared between tests), and deletes it on exit (or optionally doesn't, if you want to check its contents after the test run).

这是另一个解决方案,受到其他一些答案的启发。这个适合包含在测试中(例如 rspec 或 spec_helper.rb)。它根据包含文件的名称创建一个临时目录,将其存储在一个实例变量中,以便它在测试期间持续存在(但不在测试之间共享),并在退出时将其删除(或可选地不删除,如果您想在测试运行后检查其内容)。

def temp_dir options = {:remove => true}
  @temp_dir ||= begin
    require 'tmpdir'
    require 'fileutils'
    called_from = File.basename caller.first.split(':').first, ".rb"
    path = File.join(Dir::tmpdir, "#{called_from}_#{Time.now.to_i}_#{rand(1000)}")
    Dir.mkdir(path)
    at_exit {FileUtils.rm_rf(path) if File.exists?(path)} if options[:remove]
    File.new path
  end
end

(You could also use Dir.mktmpdir(which has been around since Ruby 1.8.7) instead of Dir.mkdirbut I find the API of that method confusing, not to mention the naming algorithm.)

(您也可以使用Dir.mktmpdir(从 Ruby 1.8.7 开始就已经存在)而不是Dir.mkdir,但我发现该方法的 API 令人困惑,更不用说命名算法了。)

Usage example (and another useful test method):

使用示例(以及另一种有用的测试方法):

def write name, contents = "contents of #{name}"
  path = "#{temp_dir}/#{name}"
  File.open(path, "w") do |f|
    f.write contents
  end
  File.new path
end

describe "#write" do
  before do
    @hello = write "hello.txt"
    @goodbye = write "goodbye.txt", "farewell"
  end

  it "uses temp_dir" do
    File.dirname(@hello).should == temp_dir
    File.dirname(@goodbye).should == temp_dir
  end

  it "writes a default value" do
    File.read(@hello).should == "contents of hello.txt"
  end

  it "writes a given value" do
    # since write returns a File instance, we can call read on it
    @goodbye.read.should == "farewell" 
  end
end


Update: I've used this code to kickstart a gem I'm calling fileswhich intends to make it super-easy to create directories and files for temporary (e.g. unit test) use. See https://github.com/alexch/filesand https://rubygems.org/gems/files. For example:

更新:我已经使用这段代码来启动我正在调用的 gem files,它旨在让创建临时(例如单元测试)使用的目录和文件变得超级容易。请参阅https://github.com/alexch/fileshttps://rubygems.org/gems/files。例如:

require "files"

files = Files do     # creates a temporary directory inside Dir.tmpdir
  file "hello.txt"          # creates file "hello.txt" containing "contents of hello.txt"
  dir "web" do              # creates directory "web"
    file "snippet.html",    # creates file "web/snippet.html"...
      "<h1>Fix this!</h1>"  # ...containing "<h1>Fix this!</h1>"
    dir "img" do            # creates directory "web/img"
      file File.new("data/hello.png")            # containing a copy of hello.png
      file "hi.png", File.new("data/hello.png")  # and a copy of hello.png named hi.png
    end
  end
end                         # returns a string with the path to the directory

回答by inger

I started to tackle this by hiHymaning Tempfile, see below. It should clean itself up as Tempfile does, but doesn't always yet.. It's yet to delete files in the tempdir. Anyway I share this here, might be useful as a starting point.

我开始通过劫持 Tempfile 来解决这个问题,见下文。它应该像 Tempfile 一样自行清理,但并不总是如此。它尚未删除 tempdir 中的文件。无论如何,我在这里分享这个,作为一个起点可能很有用。

require 'tempfile'
class Tempdir < Tempfile
  require 'tmpdir'
  def initialize(basename, tmpdir = Dir::tmpdir)
    super
    p = self.path
    File.delete(p)
    Dir.mkdir(p)
  end
  def unlink # copied from tempfile.rb
    # keep this order for thread safeness
    begin
      Dir.unlink(@tmpname) if File.exist?(@tmpname)
      @@cleanlist.delete(@tmpname)
      @data = @tmpname = nil
      ObjectSpace.undefine_finalizer(self)
    rescue Errno::EACCES
      # may not be able to unlink on Windows; just ignore
    end
  end  
end

This can be used the same way as Tempfile, eg:

这可以像 Tempfile 一样使用,例如:

 Tempdir.new('foo')

All methods on Tempfile , and in turn, File should work. Just briefly tested it, so no guarantees.

Tempfile 上的所有方法,反过来, File 应该工作。只是简单地测试了它,所以不能保证。

回答by JT.

Check out the Ruby STemp library: http://ruby-stemp.rubyforge.org/rdoc/

查看 Ruby STemp 库:http://ruby-stemp.rubyforge.org/rdoc/

If you do something like this:

如果你做这样的事情:

dirname = STemp.mkdtemp("#{Dir.tmpdir}/directory-name-template-XXXXXXXX")

dirname will be a string that points to a directory that's guaranteed not to exist previously. You get to define what you want the directory name to start with. The X's get replaced with random characters.

dirname 将是一个字符串,指向一个保证以前不存在的目录。您可以定义您希望目录名称以什么开头。X 被替换为随机字符。

EDIT: someone mentioned this didn't work for them on 1.9, so YMMV.

编辑:有人提到这在 1.9 上对他们不起作用,所以 YMMV。