Spec-Zone.ru › Ruby 4.0

class Tempfile

Вспомогательный класс для работы с временными файлами.

Существует два способа создания временного файла:

  • Tempfile.create (рекомендуется)

  • Tempfile.new и Tempfile.open (в основном для обратной совместимости, не рекомендуются)

Tempfile.create создает обычный объект File. Время удаления файла предсказуемо. Кроме того, поддерживается метод открытия и удаления, при котором временный файл удаляется сразу после создания.

Tempfile.new и Tempfile.open создают объект Tempfile. Созданный файл удаляется сборщиком мусора (GC). Время удаления файла непредсказуемо.

Краткое описание

require 'tempfile'

# Tempfile.create with a block
# The filename are chosen 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.new и Tempfile.open

Этот раздел не относится к Tempfile.create, поскольку он возвращает объект File (а не объект Tempfile).

При создании объекта Tempfile создается временный файл с уникальным именем. Объект Tempfile ведет себя так же, как объект File, и с ним можно выполнять все обычные файловые операции: читать и записывать данные, изменять разрешения и т. д. Поэтому, хотя этот класс явно не документирует все методы экземпляра, поддерживаемые классом File, фактически с объектом Tempfile можно вызывать любой метод экземпляра File.

Объект Tempfile имеет финализатор для удаления временного файла. Это означает, что временный файл удаляется сборщиком мусора (GC). Это может привести к нескольким проблемам:

  • При длительных интервалах между запусками GC и консервативной работе GC могут накапливаться неудаленные временные файлы.

  • Временные файлы не удаляются при аварийном завершении Ruby (например, из-за SIGKILL или SEGV).

Для методов Tempfile.new и Tempfile.open существуют следующие рекомендации, принятые для обратной совместимости.

Явное закрытие

Когда объект Tempfile удаляется сборщиком мусора или завершается интерпретатор Ruby, связанный с ним временный файл автоматически удаляется. Это означает, что после использования объект Tempfile необязательно удалять явно, хотя это считается хорошей практикой: если явно не удалять неиспользуемые временные файлы, их большое количество может оставаться в файловой системе до запуска сборщика мусора. Наличие этих временных файлов может затруднить выбор имени для нового файла Tempfile.

Поэтому всегда следует вызывать unlink или закрывать файл в блоке ensure, например:

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, и вам не нужно знать его имя.

Кроме того, это гарантирует удаление временного файла даже при аварийном завершении Ruby. Операционная система освобождает место, занимаемое временным файлом, когда файл закрывается или процесс Ruby завершается (обычным или аварийным образом).

Например, удаление сразу после создания может пригодиться в ситуации, когда нужен большой буфер байтов, который трудно разместить в оперативной памяти, например при написании веб-сервера, которому требуется буферизовать данные загружаемого клиентом файла.

Метод ‘Tempfile.create(anonymous: true)` поддерживает такое поведение. Он также работает в Windows.

Примечания

Метод выбора имени файла в Tempfile потокобезопасен и безопасен при работе нескольких процессов: он гарантирует, что никакие другие потоки или процессы не выберут то же имя.

Однако сам объект Tempfile может быть не полностью потокобезопасным. Если один и тот же объект Tempfile используется из нескольких потоков, следует защитить его мьютексом.

Константы

VERSION

Версия

Публичные методы класса

create (basename="", tmpdir=nil, mode: 0, anonymous: false, **options, &block) Показать исходный код
# File lib/tempfile.rb, line 558
def Tempfile.create(basename="", tmpdir=nil, mode: 0, anonymous: false, **options, &block)
  if anonymous
    create_anonymous(basename, tmpdir, mode: mode, **options, &block)
  else
    create_with_filename(basename, tmpdir, mode: mode, **options, &block)
  end
end

Создает файл в базовой файловой системе и возвращает новый объект File, связанный с этим файлом.

Если блок не задан и аргументы не переданы, создает и возвращает файл со следующими характеристиками:

  • Класс — File (не Tempfile).

  • Каталог — системный временный каталог (зависит от системы).

  • Сгенерированное имя файла уникально в этом каталоге.

  • Разрешения — 0600; см. раздел Разрешения файлов.

  • Режим — 'w+' (режим чтения/записи, позиция установлена в конец файла).

Удаление временного файла зависит от именованного аргумента anonymous и от того, задан ли блок. Описание именованного аргумента anonymous см. далее.

Пример:

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

Tempfile.create {|f|
  f.puts "foo"
  f.rewind
  f.read                # => "foo\n"
  f.path                # => "/tmp/20240524-380207-oma0ny"
  File.exist?(f.path)   # => true
}                       # The file is removed at block exit.

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) {|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"
}

Аргумент 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>
    

При аргументах basename и tmpdir файл создается в каталоге tmpdir:

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

Именованные аргументы mode и options передаются непосредственно методу File.open:

  • Значение, переданное для mode, должно быть целым числом; его можно задать как логическое ИЛИ констант, определенных в File::Constants.

  • Описание options см. в разделе Параметры открытия.

Именованный аргумент anonymous определяет, когда файл будет удален.

  • anonymous=false (по умолчанию), если блок не задан: файл не удаляется.

  • anonymous=false (по умолчанию), если блок задан: файл удаляется после завершения блока.

  • anonymous=true, если блок не задан: файл удаляется перед возвратом.

  • anonymous=true, если блок задан: файл удаляется до вызова блока.

В первом случае (anonymous=false без блока) файл не удаляется автоматически. Его необходимо закрыть явно. Это позволяет переименовать файл, присвоив ему нужное имя. Если файл больше не нужен, его следует удалить явно.

Метод File#path созданного объекта файла возвращает путь к временному каталогу с завершающим символом косой черты, если anonymous имеет значение true.

Если задан блок, метод создает файл, как описано выше, передает его блоку и возвращает значение блока. Перед возвратом объект файла закрывается, а базовый файл удаляется:

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

Примечание по реализации:

Именованный аргумент anonymous=true реализован с помощью FILE_SHARE_DELETE в Windows. В Linux используется O_TMPFILE.

Связанный метод: Tempfile.new.

new (basename="", tmpdir=nil, mode: 0, **options) Показать исходный код
# File lib/tempfile.rb, line 219
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
  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

  super(tmpfile)

  @finalizer_manager = FinalizerManager.new(__getobj__.path)
  @finalizer_manager.register(self, __getobj__)
end

Создает файл в базовой файловой системе и возвращает новый объект Tempfile, связанный с этим файлом.

По возможности рассмотрите использование вместо него метода Tempfile.create, который:

  • Позволяет избежать снижения производительности из-за делегирования, возникающего при вызове Tempfile.new метода суперкласса DelegateClass(File).

  • Не полагается на финализатор для закрытия и удаления файла, работа которого может быть ненадежной.

Создает и возвращает файл со следующими характеристиками:

  • Класс — 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>
    

При аргументах basename и tmpdir файл создается в каталоге tmpdir:

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

Именованные аргументы mode и options передаются непосредственно методу File.open:

  • Значение, переданное с mode, должно быть целым числом; его можно задать как логическое ИЛИ констант, определенных в File::Constants.

  • Описание options см. в разделе Параметры открытия.

Связанный метод: Tempfile.create.

Вызывает метод суперкласса
open (*args, **kw) { |tempfile| ... } Показать исходный код
# File lib/tempfile.rb, line 439
def open(*args, **kw)
  tempfile = new(*args, **kw)

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

Создает новый объект Tempfile.

Этот метод не рекомендуется и существует главным образом для обратной совместимости. Вместо него используйте Tempfile.create: он позволяет избежать затрат на делегирование, не полагается на финализатор и удаляет файл при передаче блока.

Метод Tempfile.open по-прежнему подходит, если необходимо, чтобы файл Tempfile удалялся финализатором, и невозможно явно определить, в какой части программы файл Tempfile можно безопасно удалить.

Если блок не задан, этот метод является синонимом 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

Публичные методы экземпляра

close (unlink_now=false) Показать исходный код
# File lib/tempfile.rb, line 279
def close(unlink_now=false)
  _close
  unlink if unlink_now
end

Закрывает файл. Если unlink_now имеет значение true, файл удаляется после закрытия. Разумеется, если файл не удален сейчас, позднее можно вызвать unlink.

Если временный файл не удалить явно, его удаление откладывается до финализации объекта.

close! () Показать исходный код
# File lib/tempfile.rb, line 286
def close!
  close(true)
end

Закрывает и удаляет файл. Имеет тот же эффект, что и вызов close(true).

delete ()
Псевдоним для: unlink
length ()
Псевдоним для: size
open () Показать исходный код
# File lib/tempfile.rb, line 257
def open
  _close

  mode = @mode & ~(File::CREAT|File::EXCL)
  __setobj__(File.open(__getobj__.path, mode, **@opts))

  @finalizer_manager.register(self, __getobj__)

  __getobj__
end

Открывает файл или повторно открывает его в режиме «r+».

path () Показать исходный код
# File lib/tempfile.rb, line 341
def path
  @unlinked ? nil : __getobj__.path
end

Возвращает полный путь к временному файлу. Если был вызван метод unlink, возвращается nil.

size () Показать исходный код
# File lib/tempfile.rb, line 347
def size
  if !__getobj__.closed?
    __getobj__.size # File#size calls rb_io_flush_raw()
  else
    File.size(__getobj__.path)
  end
end

Возвращает размер временного файла. Перед определением размера буфер IO сбрасывается; это является побочным эффектом.

Также имеет псевдоним: length
unlink () Показать исходный код
# File lib/tempfile.rb, line 323
def unlink
  return if @unlinked
  begin
    File.unlink(__getobj__.path)
  rescue Errno::ENOENT
  rescue Errno::EACCES
    # may not be able to unlink on Windows; just ignore
    return
  end

  @finalizer_manager.unlinked = true

  @unlinked = true
end

Удаляет файл из файловой системы. После использования файл всегда следует удалять, как объясняется в разделе рекомендаций «Явное закрытие» в обзоре класса Tempfile:

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

Удаление до закрытия

В POSIX-системах файл можно удалить до его закрытия. Эта практика подробно описана в обзоре класса Tempfile (раздел «Удаление сразу после создания»); дополнительные сведения см. там.

Однако удаление до закрытия может не поддерживаться операционными системами, отличными от POSIX. Наиболее заметный пример — Microsoft Windows: попытка удалить незакрытый файл приводит к ошибке, которую этот метод молча игнорирует. Если вы хотите по возможности удалять файл до закрытия, напишите код следующим образом:

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
Также имеет псевдоним: delete

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API