Ruby 2.4

Tempfile

class Tempfile

Parent:DelegateClass(File)

用于管理临时文件的实用程序类。当您创建一个Tempfile对象时,它将创建一个具有唯一文件名的临时文件。Tempfile对象的行为与File对象相似,您可以对其执行所有常见的文件操作:读取数据,写入数据,更改权限等。因此,尽管此类不明确记录File支持的所有实例方法,但您实际上可以调用Tempfile对象上的任何File实例方法。

概要

require 'tempfile' file = Tempfile.new('foo') file.path # => A unique filename in the OS's temp directory, # e.g.: "/tmp/foo.24722.0" # This filename contains 'foo' in its basename. file.write("hello world") file.rewind file.read # => "hello world" file.close file.unlink # deletes the temp file

好的做法

显式关闭

当一个Tempfile对象被垃圾收集时,或者当Ruby解释器退出时,其相关的临时文件将被自动删除。这意味着在使用后没有必要显式删除一个临时文件,尽管这样做很好:不明确地删除未使用的临时文件可能会在文件系统上留下大量的临时文件,直到它们被垃圾收集为止。这些临时文件的存在可能会导致难以确定新的Tempfile文件名。

因此,应该始终在确保块中调用取消链接或关闭,如下所示:

file = Tempfile.new('foo') begin ...do something with file... ensure file.close file.unlink # deletes the temp file end

创建后取消链接

在POSIX系统上,可以在创建文件之后以及关闭文件之前解除文件的链接。这会在不关闭文件句柄的情况下删除文件系统条目,因此它确保只有已打开文件句柄的进程才能访问文件内容。强烈建议您如果不希望任何其他进程能够读取或写入Tempfile,并且不需要知道Tempfile的文件名,则可以执行此操作。

例如,创建unlink-after-a的实际用例是这样的:你需要一个大的字节缓冲区,这个缓冲区太大而不适合放在RAM中,例如,当你正在编写web服务器并且你想要缓冲客户端的文件上传时数据。

请参阅取消链接了解更多信息和代码示例。

次要笔记

Tempfile的文件名选取方法既是线程安全的也是进程间安全的:它保证没有其他线程或进程会选择相同的文件名。

Tempfile本身可能并不完全是线程安全的。如果你从多个线程访问同一个Tempfile对象,那么你应该用一个互斥锁来保护它。

公共类方法

create(basename="", tmpdir=nil, mode: 0, **options) { |tmpfile| ... } 显示源

像平常一样创建一个临时文件File对象(不是Tempfile)。它不使用终结器和委托。

如果没有给出块,除了创建File而不是Tempfile之外,它与:: new类似。创建的文件不会自动删除。您应该使用File.unlink将其删除。

如果给出了一个块,那么将构造一个File对象,并将该对象作为参数调用该块。File对象将自动关闭,并在块终止后删除临时文件。该调用返回该块的值。

无论如何,所有参数(+ * args +)都将被视为:: new。

Tempfile.create('foo', '/home/temp') do |f| ... do something with f ... end

# File lib/tempfile.rb, line 325 def Tempfile.create(basename="", tmpdir=nil, mode: 0, **options) tmpfile = nil Dir::Tmpname.create(basename, tmpdir, options) do |tmpname, n, opts| mode |= File::RDWR|File::CREAT|File::EXCL opts[:perm] = 0600 tmpfile = File.open(tmpname, mode, opts) end if block_given? begin yield tmpfile ensure tmpfile.close File.unlink tmpfile end else tmpfile end end

new(basename = "", tmpdir = Dir.tmpdir, options) 显示源

创建一个权限为0600(=只能由所有者读写)的临时文件,并使用模式“w +”打开它。

basename参数用于确定临时文件的名称。您可以传递一个String或一个包含2个String元素的数组。在前一种形式中,临时文件的基本名称将以给定的字符串开头。在后一种形式中,临时文件的基本名称将从数组的第一个元素开始,并以第二个元素结束。例如:

file = Tempfile.new('hello') file.path # => something like: "/tmp/hello2843-8392-92849382--0" # Use the Array form to enforce an extension in the filename: file = Tempfile.new(['hello', '.jpg']) file.path # => something like: "/tmp/hello2843-8392-92849382--0.jpg"

临时文件将被放置在tmpdir参数指定的目录中。默认情况下,这是Dir.tmpdir。当$ SAFE> 0且给定tmpdir被污染时,它使用'/ tmp'作为临时目录。请注意,ENV值默认情况下被污染,并且Dir.tmpdir返回值可能来自环境变量(例如$TMPDIR)。

file = Tempfile.new('hello', '/home/aisaka') file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"

您也可以传递选项散列。在引擎盖下,Tempfile使用创建临时文件File.open。这些选项将被传递给File.open。这对于指定编码选项非常有用,例如:

Tempfile.new('hello', '/home/aisaka', :encoding => 'ascii-8bit') # You can also omit the 'tmpdir' parameter: Tempfile.new('hello', :encoding => 'ascii-8bit')

例外

如果:: new在有限次数的尝试中找不到唯一的文件名,则会引发异常。

调用超类方法

# File lib/tempfile.rb, line 125 def initialize(basename="", tmpdir=nil, mode: 0, **options) warn "Tempfile.new doesn't call the given block." if block_given? @unlinked = false @mode = mode|File::RDWR|File::CREAT|File::EXCL ::Dir::Tmpname.create(basename, tmpdir, options) do |tmpname, n, opts| opts[:perm] = 0600 @tmpfile = File.open(tmpname, @mode, opts) @opts = opts.freeze end ObjectSpace.define_finalizer(self, Remover.new(@tmpfile)) super(@tmpfile) end

open(*args) { |tempfile| ... }显示源

创建一个新的Tempfile。

如果没有给出块,这是:: new的同义词。

如果给出了一个块,那么将构造一个Tempfile对象,并且该块以所述对象作为参数运行。Tempfile对象将在块终止后自动关闭。该调用返回该块的值。

无论如何,所有参数(+ * args +)都会被传递给:: new。

Tempfile.open('foo', '/home/temp') do |f| ... do something with f ... end # Equivalent: f = Tempfile.open('foo', '/home/temp') begin ... do something with f ... ensure f.close end

# File lib/tempfile.rb, line 289 def open(*args) tempfile = new(*args) if block_given? begin yield(tempfile) ensure tempfile.close end else tempfile end end

公共实例方法

close(unlink_now=false)显示源

关闭文件。如果unlink_now为真,那么文件在关闭后将被取消链接(删除)。当然,如果你现在不解除链接,你可以选择稍后调用unlink。

如果您没有明确取消临时文件的链接,则删除操作将延迟到对象完成时为止。

# File lib/tempfile.rb, line 159 def close(unlink_now=false) _close unlink if unlink_now end

close!() 显示源

关闭并取消链接(删除)文件。具有与所谓的相同的效果close(true)

# File lib/tempfile.rb, line 166 def close! close(true) end

delete()

别名为:取消链接

length()

别名为:大小

open() 显示源

打开或重新打开模式为“r +”的文件。

# File lib/tempfile.rb, line 141 def open _close mode = @mode & ~(File::CREAT|File::EXCL) @tmpfile = File.open(@tmpfile.path, mode, @opts) __setobj__(@tmpfile) end

path() 显示源

返回临时文件的完整路径名称。如果取消链接被调用,这将是零。

# File lib/tempfile.rb, line 219 def path @unlinked ? nil : @tmpfile.path end

size() 显示源

返回临时文件的大小。作为副作用,IO缓冲区在确定大小之前被刷新。

# File lib/tempfile.rb, line 225 def size if !@tmpfile.closed? @tmpfile.size # File#size calls rb_io_flush_raw() else File.size(@tmpfile.path) end end

另外别名为:长度

unlink() 显示源

从文件系统取消链接(删除)文件。在使用该文件后,应始终取消链接,如Tempfile概述中的“显式关闭”良好实践部分中所述:

file = Tempfile.new('foo') begin ...do something with file... ensure file.close file.unlink # deletes the temp file end

取消链接 - 前关闭

在POSIX系统上,可以在关闭文件之前取消链接。Tempfile概述中详细介绍了这种做法(“创建后取消链接”一节); 请参阅那里获取更多信息。

但是,非POSIX操作系统可能不支持unlink-before-close。Microsoft Windows是最值得关注的案例:取消关闭非关闭文件将导致错误,该方法将默默忽略。如果你想尽可能练习unlink-before-close,那么你应该写下如下代码:

file = Tempfile.new('foo') file.unlink # On Windows this silently fails. begin ... do something with file ... ensure file.close! # Closes the file handle. If the file wasn't unlinked # because #unlink failed, then this method will attempt # to do so again. end

# File lib/tempfile.rb, line 203 def unlink return if @unlinked begin File.unlink(@tmpfile.path) rescue Errno::ENOENT rescue Errno::EACCES # may not be able to unlink on Windows; just ignore return end ObjectSpace.undefine_finalizer(self) @unlinked = true end

另外别名为:删除