Spec-Zone.ru › Ruby 3.3

класс Tempfile

Родитель:
DelegateClass(File)

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

Синопсис

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.

Поэтому всегда следует вызывать 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, и вам также не нужно знать имя файла Tempfile.

Например, практическое применение unlink-после-создания было бы таким: вам нужен большой буфер байтов, слишком большой для комфортного размещения в ОЗУ, например, когда вы пишете веб-сервер и хотите буферизовать данные загружаемого клиентом файла.

Дополнительную информацию и пример кода см. в unlink.

Небольшие замечания

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

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

Константы

VERSION

Открытые методы класса

create(basename="", tmpdir=nil, mode: 0, **options) { |tmpfile| ... } Показать исходный код
# 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

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

Без блока и без аргументов создаёт и возвращает файл с:

  • Class — 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>
    

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

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

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

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

  • Для options, см. Параметры открытия.

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

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

Связанное: Tempfile.new.

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

Создаёт файл в файловой системе; возвращает новый объект 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>
    

С аргументами 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 366
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 208
def close(unlink_now=false)
  _close
  unlink if unlink_now
end

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

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

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

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

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() Показать исходный код
# 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

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

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

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

size() Показать исходный код
# 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

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

Также алиасируется как: length
unlink() Показать исходный код
# File lib/tempfile.rb, line 252
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
  ObjectSpace.undefine_finalizer(@finalizer_obj)
  @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

Закрытые методы экземпляра

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

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

Spec-Zone.ru

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