使用Ruby on Rails获取没有任何内容的临时目录的最佳方法是什么?我需要API与跨平台兼容。 stdlib tmpdir无效。
答案 0 :(得分:48)
Dir
对象有一个方法mktmpdir,它创建一个临时目录:
require 'tmpdir' # Not needed if you are using rails.
Dir.mktmpdir do |dir|
puts "My new temp dir: #{dir}"
end
执行块后将删除临时目录。
答案 1 :(得分:20)
Ruby核心中的Dir#tmpdir
函数(不是您链接到的stdlib)应该是跨平台的。
要使用此功能,您需要require 'tmpdir'
。
答案 2 :(得分:13)
我现在正在使用的普通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
当您的方法完成后,临时目录将自动删除。
答案 3 :(得分:2)
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)
适合我。
答案 4 :(得分:1)
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。
答案 5 :(得分:0)
我开始通过劫持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上的所有方法,反过来,File应该有效。 只是简单地测试了它,所以没有保证。
答案 6 :(得分:0)
查看Ruby STemp库:http://ruby-stemp.rubyforge.org/rdoc/
如果您这样做:
dirname = STemp.mkdtemp("#{Dir.tmpdir}/directory-name-template-XXXXXXXX")
dirname将是一个字符串,指向一个保证以前不存在的目录。您可以定义目标名称的开头内容。 X被随机字符取代。
编辑:有人提到这对于他们在1.9上没有用,所以YMMV。答案 7 :(得分:0)
更新: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令人困惑,更不用说命名算法。)< / p>
用法示例(和另一种有用的测试方法):
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
更新:我已经使用这段代码来启动我正在调用的files
一个gem,它打算使用它来创建用于临时(例如单元测试)的目录和文件变得非常容易。请参阅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"...
"<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
答案 8 :(得分:0)
您可以使用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.mktmpdir
在Dir.tmpdir
下创建一个临时目录(您需要require 'tmpdir'
才能查看评估结果)。
如果您想使用自己的路径,Dir.mktmpdir
如果给出非零值,则会选择第二个参数 tmpdir 。 E.g。
Dir.mktmpdir(nil, "/var/tmp") { |dir| "dir is '/var/tmp/d...'" }