Tempfile 類別

用於管理暫存檔案的實用程式類別。當您建立 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 並非必要,但這是一個良好的做法:不明確刪除未使用的 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 的檔名,強烈建議您執行此操作。

例如,建立後取消連結的實際使用案例如下:您需要一個過大的位元組緩衝區,而這個緩衝區太大,無法舒適地放入 RAM 中,例如當您撰寫網路伺服器時,您想要緩衝客戶端的檔案上傳資料。

請參閱 unlink 以取得更多資訊和程式碼範例。

次要注意事項

Tempfile 的檔案名稱挑選方法是執行緒安全且跨處理程序安全的:它保證其他執行緒或處理程序不會挑選相同的檔案名稱。

不過,Tempfile 本身可能不是完全執行緒安全的。如果您從多個執行緒存取相同的 Tempfile 物件,則應使用互斥鎖保護它。

常數

VERSION

公開類別方法

create(basename="", tmpdir=nil, mode: 0, **options) { |tmpfile| ... } 按一下以切換原始程式碼

在底層檔案系統中建立一個檔案;根據該檔案傳回新的 File 物件。

如果沒有給定區塊和引數,則建立並傳回其

  • 類別File(不是 Tempfile)的檔案。

  • 目錄是系統暫存目錄(與系統相關)。

  • 產生的檔案名稱在該目錄中是唯一的。

  • 權限為 0600;請參閱 檔案權限

  • 模式為 'w+'(讀寫模式,定位在結尾)。

如果沒有區塊,則檔案不會自動移除,因此應該明確移除。

範例

f = Tempfile.create     # => #<File:/tmp/20220505-9795-17ky6f6>
f.class                 # => File
f.path                  # => "/tmp/20220505-9795-17ky6f6"
f.stat.mode.to_s(8)     # => "100600"
File.exist?(f.path)     # => true
File.unlink(f.path)
File.exist?(f.path)     # => false

如果給定引數 basename,則可能是下列其中之一

  • 字串:產生的檔案名稱以 basename 開頭

    Tempfile.create('foo') # => #<File:/tmp/foo20220505-9795-1gok8l9>
    
  • 兩個字串的陣列 [prefix, suffix]:產生的檔案名稱以 prefix 開頭並以 suffix 結尾

    Tempfile.create(%w/foo .jpg/) # => #<File:/tmp/foo20220505-17839-tnjchh.jpg>
    

使用引數 basenametmpdir,檔案會建立在目錄 tmpdir

Tempfile.create('foo', '.') # => #<File:./foo20220505-9795-1emu6g8>

關鍵字引數 modeoptions 會直接傳遞給方法 File.open

  • 使用 mode 給出的值必須是整數,而且可以表示為 File::Constants 中定義的常數的邏輯 OR。

  • 對於 options,請參閱 開啟選項

如果給定區塊,則會建立檔案(如上所述),將其傳遞給區塊,並傳回區塊的值;在傳回之前,檔案物件會關閉,而底層檔案會移除

Tempfile.create {|file| file.path } # => "/tmp/20220505-9795-rkists"

相關:Tempfile.new

# File lib/tempfile.rb, line 438
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
      unless tmpfile.closed?
        if File.identical?(tmpfile, tmpfile.path)
          unlinked = File.unlink tmpfile.path rescue nil
        end
        tmpfile.close
      end
      unless unlinked
        begin
          File.unlink tmpfile.path
        rescue Errno::ENOENT
        end
      end
    end
  else
    tmpfile
  end
end
new(basename="", tmpdir=nil, mode: 0, **options) 按一下以切換原始程式碼

在底層檔案系統中建立一個檔案;根據該檔案傳回新的 Tempfile 物件。

如果可能,請考慮改用 Tempfile.create,它

  • 避免委派效能成本,在 Tempfile.new 呼叫其超類別 DelegateClass(File) 時會發生。

  • 不依賴完成器來關閉和取消連結檔案,這可能不可靠。

建立並傳回其

  • Class 為 Tempfile(而非 File,如 Tempfile.create)的檔案。

  • 目錄是系統暫存目錄(與系統相關)。

  • 產生的檔案名稱在該目錄中是唯一的。

  • 權限為 0600;請參閱 檔案權限

  • 模式為 'w+'(讀寫模式,定位在結尾)。

當 Tempfile 物件死亡並被垃圾收集器回收時,會移除底層檔案。

範例

f = Tempfile.new # => #<Tempfile:/tmp/20220505-17839-1s0kt30>
f.class               # => Tempfile
f.path                # => "/tmp/20220505-17839-1s0kt30"
f.stat.mode.to_s(8)   # => "100600"
File.exist?(f.path)   # => true
File.unlink(f.path)   #
File.exist?(f.path)   # => false

如果給定引數 basename,則可能是下列其中之一

  • 字串:產生的檔案名稱以 basename 開頭

    Tempfile.new('foo') # => #<Tempfile:/tmp/foo20220505-17839-1whk2f>
    
  • 兩個字串的陣列 [prefix, suffix]:產生的檔案名稱以 prefix 開頭並以 suffix 結尾

    Tempfile.new(%w/foo .jpg/) # => #<Tempfile:/tmp/foo20220505-17839-58xtfi.jpg>
    

使用引數 basenametmpdir,檔案會建立在目錄 tmpdir

Tempfile.new('foo', '.') # => #<Tempfile:./foo20220505-17839-xfstr8>

關鍵字引數 modeoptions 會直接傳遞給方法 File.open

  • 使用 mode 給出的值必須是整數,而且可以表示為 File::Constants 中定義的常數的邏輯 OR。

  • 對於 options,請參閱 開啟選項

相關:Tempfile.create

呼叫超類別方法
# File lib/tempfile.rb, line 150
def initialize(basename="", tmpdir=nil, mode: 0, **options)
  warn "Tempfile.new doesn't call the given block.", uplevel: 1 if block_given?

  @unlinked = false
  @mode = mode|File::RDWR|File::CREAT|File::EXCL
  @finalizer_obj = Object.new
  tmpfile = nil
  ::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(@finalizer_obj, Remover.new(tmpfile.path))
  ObjectSpace.define_finalizer(self, Closer.new(tmpfile))

  super(tmpfile)
end

受保護的類別方法

open(*args, **kw) { |tempfile| ... } 按一下以切換來源

建立新的 Tempfile

不建議使用此方法,它主要存在於向後相容性。請改用 Tempfile.create,它避免委派成本,不依賴完成器,並在給定區塊時取消連結檔案。

如果您需要 Tempfile 由完成器取消連結,而且無法明確知道程式中可以在哪裡安全地取消連結 Tempfile,則 Tempfile.open 仍然合適。

如果沒有給定區塊,這會成為 Tempfile.new 的同義詞。

如果給定區塊,則會建構 Tempfile 物件,並以 Tempfile 物件為引數執行區塊。區塊終止後,Tempfile 物件會自動關閉。但是,不會取消連結檔案,需要使用 Tempfile#close!Tempfile#unlink 手動取消連結。完成器會嘗試取消連結,但不要依賴它,因為它可能會讓檔案保留在磁碟上比預期時間長。例如,在 CRuby 上,完成器可能會因為保守的堆疊掃描和未使用的記憶體中留下的參考而延遲。

呼叫會傳回區塊的值。

在任何情況下,所有引數(*args)都會傳遞給 Tempfile.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 366
def open(*args, **kw)
  tempfile = new(*args, **kw)

  if block_given?
    begin
      yield(tempfile)
    ensure
      tempfile.close
    end
  else
    tempfile
  end
end

公開的實例方法

close(unlink_now=false) 按一下以切換來源

關閉檔案。如果 unlink_now 為 true,則關閉後會取消連結(刪除)檔案。當然,如果您現在不取消連結,您可以選擇稍後呼叫 unlink

如果您沒有明確取消連結暫存檔,移除動作會延遲到物件最終確定。

# File lib/tempfile.rb, line 208
def close(unlink_now=false)
  _close
  unlink if unlink_now
end
close!() 按一下以切換來源

關閉並取消連結 (刪除) 檔案。效果與呼叫 close(true) 相同。

# File lib/tempfile.rb, line 215
def close!
  close(true)
end
delete()
別名:unlink
initialize_clone(other) 按一下以切換來源
呼叫超類別方法
# File lib/tempfile.rb, line 174
def initialize_clone(other)
  initialize_copy_iv(other)
  super(other)
  ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
end
initialize_dup(other) 按一下以切換來源
呼叫超類別方法
# File lib/tempfile.rb, line 168
def initialize_dup(other)
  initialize_copy_iv(other)
  super(other)
  ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
end
length()
別名:size
open() 按一下以切換來源

以「r+」模式開啟或重新開啟檔案。

# File lib/tempfile.rb, line 188
def open
  _close
  ObjectSpace.undefine_finalizer(self)
  mode = @mode & ~(File::CREAT|File::EXCL)
  __setobj__(File.open(__getobj__.path, mode, **@opts))
  ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
  __getobj__
end
path() 按一下以切換來源

傳回暫存檔的完整路徑名稱。如果已呼叫 unlink,則會為 nil。

# File lib/tempfile.rb, line 268
def path
  @unlinked ? nil : __getobj__.path
end
size() 按一下以切換來源

傳回暫存檔的大小。作為副作用,IO 緩衝區會在判斷大小前先清除。

# File lib/tempfile.rb, line 274
def size
  if !__getobj__.closed?
    __getobj__.size # File#size calls rb_io_flush_raw()
  else
    File.size(__getobj__.path)
  end
end
別名:length

私有實例方法

initialize_copy_iv(other) 按一下以切換來源
# File lib/tempfile.rb, line 180
        def initialize_copy_iv(other)
  @unlinked = other.unlinked
  @mode = other.mode
  @opts = other.opts
  @finalizer_obj = other.finalizer_obj
end