Разница между переназначением и повторным открытием в потоках ввода-вывода Ruby - PullRequest
3 голосов
/ 13 июля 2011

В Ruby, в чем разница между переназначением потока ввода-вывода и использованием метода IO#reopen? Другими словами, в чем разница между

$stdout = newfile

и

$stdout.reopen(newfile)

Ответы [ 3 ]

3 голосов
/ 13 июля 2011

Таким образом, в основном, повторное открытие будет связывать $stdout с newfile stream => $stdout, а newfile будет двумя экземплярами File, связанными с одним и тем же потоком.

= фактически назначитnewfile Экземпляр файла в $stdout => $stdout и newfile будет двумя переменными, указывающими на один и тот же экземпляр файла.

Последствия:

При использовании reopen любое изменениена экземпляре (который не влияет на сам поток) не будет отражен в другом экземпляре.

= Пример:

a = File.new('name')
b = File.new('name')

a.lineno #=> 0
b.lineno #=> 0

a.lineno = 3

a.lineno #=> 3
b.lineno #=> 0

b = a 

a.lineno #=> 3
b.lineno #=> 3

a.lineno = 0

a.lineno #=> 0
b.lineno #=> 0

reopen пример:

a = File.new('name')
b = File.new('name')

a.lineno #=> 0
b.lineno #=> 0

a.lineno = 3

a.lineno #=> 3
b.lineno #=> 0

b.reopen(a)

a.lineno #=> 3
b.lineno #=> 3

a.lineno = 0

a.lineno #=> 0
b.lineno #=> 3
0 голосов
/ 13 сентября 2017

Разница важна, когда вы запускаете дочерние процессы.

Назначение:

$stdout = File.open("/dev/null", "w")
system "ls"
warn $stdout.fileno  # file descriptor number

Вывод - обратите внимание, как вывод system по-прежнему отображался:

1.txt 2.txt
7

Переоформление:

$stdout.reopen("/dev/null")
system "ls"
warn $stdout.fileno

Вывод - вывод system был отправлен на /dev/null:

1

Резюме:

Переназначение $stdout, $stdin или $stderr влияет только на текущий процесс ruby. Дочерний процесс записывает свой собственный стандартный вывод в файловый дескриптор (FD) 1, считывает стандартный ввод из FD 0 и записывает диагностический вывод в FD 2.

Если вы хотите, чтобы потомок унаследовал изменение, вам нужно снова открыть поток, потому что он повторно использует дескриптор файла. Обратите внимание, что на ребенка влияет только, если вы reopen до запуска ребенка.

Один вариант использования: вы пишете скрипт-демон (или другой скрипт, который должен продолжать работать после выхода из системы). Рекомендуется снова открыть все 3 стандартных потока до /dev/null, в противном случае вы можете получить прерванный канал, если сценарий или дочерний процесс попытается использовать потоки.

0 голосов
/ 13 июля 2011

Предыдущий IO сбрасывается и закрывается в последнем (reopen) случае, как мне кажется.

Добавлено: Сравнить вывод:

$stdout.write("Buffered")
$stdout = $stderr
$stdout.write("After assignment")

и

$stdout.write("Buffered")
$stdout.reopen($stderr)
$stdout.write("After reopen")

(лучший способ сравнения - перенаправление вывода с использованием канала)

...