class Tempfile

一个用于管理临时文件的实用工具类。

有两种创建临时文件的方法:

Tempfile.create 创建一个普通的 File 对象。文件删除的时间是可预测的。此外,它还支持创建后立即删除临时文件的打开并取消链接技术。

Tempfile.newTempfile.open 创建一个 Tempfile 对象。创建的文件由 GC (终结器) 删除。文件删除的时间是不可预测的。

概要

require 'tempfile'

# Tempfile.create with a block
# The filename are choosen automatically.
# (You can specify the prefix and suffix of the filename by an optional argument.)
Tempfile.create {|f|
  f.puts "foo"
  f.rewind
  f.read                # => "foo\n"
}                       # The file is removed at block exit.

# Tempfile.create without a block
# You need to unlink the file in non-block form.
f = Tempfile.create
f.puts "foo"
f.close
File.unlink(f.path)     # You need to unlink the file.

# Tempfile.create(anonymous: true) without a block
f = Tempfile.create(anonymous: true)
# The file is already removed because anonymous.
f.path                  # => "/tmp/"  (no filename since no file)
f.puts "foo"
f.rewind
f.read                  # => "foo\n"
f.close

# Tempfile.create(anonymous: true) with a block
Tempfile.create(anonymous: true) {|f|
  # The file is already removed because anonymous.
  f.path                # => "/tmp/"  (no filename since no file)
  f.puts "foo"
  f.rewind
  f.read                # => "foo\n"
}

# Not recommended: Tempfile.new without a block
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.newTempfile.open

本节不适用于 Tempfile.create,因为它返回一个 File 对象 (而不是 Tempfile 对象)。

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

Tempfile 对象有一个终结器来删除临时文件。这意味着临时文件是通过 GC 删除的。这可能会导致几个问题:

以下是关于 Tempfile.newTempfile.open 的传统最佳实践。

显式关闭

Tempfile 对象被垃圾回收,或者当 Ruby 解释器退出时,其关联的临时文件会自动删除。这意味着没有必要在使用后显式删除 Tempfile,尽管这样做是一个好习惯:不显式删除未使用的 Tempfile 可能会在文件系统上留下大量临时文件,直到它们被垃圾回收。这些临时文件的存在会使确定新的 Tempfile 文件名更加困难。

因此,应该始终在 ensure 代码块中调用 unlink 或 close,如下所示:

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

Tempfile.create { … } 就是为此目的而存在的,并且使用起来更方便。请注意,Tempfile.create 返回 File 实例,而不是 Tempfile,这也避免了委托的开销和复杂性。

Tempfile.create('foo') do |file|
   # ...do something with file...
end

创建后取消链接

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

此外,这保证了即使 Ruby 异常退出,临时文件也会被删除。当文件关闭或 Ruby 进程退出 (正常或异常) 时,操作系统会回收临时文件的存储空间。

例如,创建后取消链接的一个实际用例是:您需要一个太大的字节缓冲区,无法舒适地放入 RAM 中,例如,当您正在编写 Web 服务器并且想要缓冲客户端的文件上传数据时。

‘Tempfile.create(anonymous: true)` 支持此行为。它也适用于 Windows。

小提示

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

然而,Tempfile 本身可能并非完全线程安全的。如果您从多个线程访问同一个 Tempfile 对象,则应使用互斥锁保护它。