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

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

Ruby核心中的Dir#tmpdir函数(不是你链接到的stdlib)应该是跨平台的。

要使用此function,您需要require 'tmpdir'

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

 require 'tmpdir' # Not needed if you are using rails. Dir.mktmpdir do |dir| puts "My new temp dir: #{dir}" end 

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

我现在正在使用的一般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 

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

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

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

 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) 

适合我。

我开始通过劫持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 

这可以与Tempfile相同的方式使用,例如:

  Tempdir.new('foo') 

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

更新: gem install files ,然后

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

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


这是另一个解决方案,受其他一些答案的启发。 这个适合包含在测试中(例如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 

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

用法示例(和另一个有用的测试方法):

 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 

更新:我已经使用此代码启动一个gem我正在调用files ,这些files旨在使创建目录和文件非常容易,以便临时(例如unit testing)使用。 请参阅https://github.com/alexch/files和https://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"... "

Fix this!

" # ...containing "

Fix this!

" 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

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

如果您这样做:

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

dirname将是一个字符串,指向一个保证以前不存在的目录。 您可以定义目标名称的开头内容。 X被随机字符取代。

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

你可以使用Dir.mktmpdir

使用块将在关闭时删除临时目录。

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

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

 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.mktmpdirDir.tmpdir下创建一个临时目录(你require 'tmpdir'才能看到它的评估结果)。

如果你想使用你自己的路径,如果给出非零值, Dir.mktmpdir会获取一个可选的第二个参数tmpdir 。 例如

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

Ruby有Dir#mktmpdir,所以就这样使用它。

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

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

或者使用流程和线程唯一的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 

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