Spec-Zone.ru › Ruby 3.1

класс 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.open('foo') do |file|
   # ...do something with file...
end

Удаление после создания

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

Например, практическое применение unlink-after-creation — это необходимость в большом буфере байтов, слишком большом для комфортной загрузки в оперативную память, например, при написании веб-сервера, где вы хотите буферизовать данные загрузки файла клиентом.

Для получения дополнительной информации и примера кода обратитесь к unlink.

Дополнительные замечания

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

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

Методы публичного класса

create(basename="", tmpdir=nil, mode: 0, **options) { |tmpfile| ... } Показать исходный код
# File lib/tempfile.rb, line 349
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 (а не Tempfile). Он не использует финализатор и делегирование, что делает его более эффективным и надёжным.

Если блок не указан, это аналогично Tempfile.new, за исключением создания объекта File вместо Tempfile. В этом случае созданный файл не удаляется автоматически. Для удаления используйте File.unlink.

Если блок указан, то будет создан объект File, и блок будет вызван с этим объектом в качестве аргумента. Объект File будет автоматически закрыт, а временный файл удалён после завершения блока, освобождая все ресурсы, созданные блоком. Вызов возвращает значение блока.

В любом случае, все аргументы (basename, tmpdir, mode, и **options) будут обработаны так же, как и для Tempfile.new.

Tempfile.create('foo', '/home/temp') do |f|
   # ... do something with f ...
end
new(basename="", tmpdir=nil, mode: 0, **options) Показать исходный код
# File lib/tempfile.rb, line 134
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
  ::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

Создаёт временный файл с разрешениями 0600 (= только чтение и запись владельцем) и открывает его в режиме “w+”.

Рекомендуется использовать Tempfile.create { … }, когда это возможно, так как этот метод избегает затрат на делегирование и не полагается на финализатор для закрытия и удаления файла, что ненадежно.

Параметр basename используется для определения имени временного файла. Вы можете передать строку String или массив Array с 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.

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')

Примечание: ключевой аргумент mode, как принятый Tempfile, может быть только числовым, комбинацией режимов, определённых в File::Constants.

Исключения

Если Tempfile.new не может найти уникальное имя файла в ограниченном числе попыток, то он сгенерирует исключение.

Вызывает метод суперкласса
open(*args, **kw) { |tempfile| ... } Показать исходный код
# File lib/tempfile.rb, line 312
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 168
def close(unlink_now=false)
  _close
  unlink if unlink_now
end

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

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

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

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

delete()
Псевдоним для: unlink
length()
Псевдоним для: size
open() Показать исходный код
# File lib/tempfile.rb, line 150
def open
  _close
  mode = @mode & ~(File::CREAT|File::EXCL)
  @tmpfile = File.open(@tmpfile.path, mode, **@opts)
  __setobj__(@tmpfile)
end

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

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

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

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

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

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

Удаляет файл из файловой системы. Всегда удаляйте файл после использования, как это описано в разделе «Явное закрытие» в обзоре 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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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