【发布时间】:2011-10-04 17:29:41
【问题描述】:
在 Ruby 中,重新分配 IO 流和使用 IO#reopen 方法有什么区别?换句话说,有什么区别
$stdout = newfile
和:
$stdout.reopen(newfile)
【问题讨论】:
标签: ruby io stdout variable-assignment
在 Ruby 中,重新分配 IO 流和使用 IO#reopen 方法有什么区别?换句话说,有什么区别
$stdout = newfile
和:
$stdout.reopen(newfile)
【问题讨论】:
标签: ruby io stdout variable-assignment
我相信在后一种 (reopen) 的情况下,之前的 IO 被刷新并关闭。
添加:比较输出:
$stdout.write("Buffered")
$stdout = $stderr
$stdout.write("After assignment")
和
$stdout.write("Buffered")
$stdout.reopen($stderr)
$stdout.write("After reopen")
(比较的最佳方法是使用管道重定向输出)
【讨论】:
所以基本上重新打开会将$stdout 与newfile 流相关联=> $stdout 和newfile 将是与同一流相关联的两个文件实例。
= 实际上会将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
【讨论】:
sync 选项如何与这两种流重定向方式一起使用?
File 实例上调用 write 方法时,sync 只会写入文件。 reopen 和= 都将sync 值“复制”到目标File 实例。切入正题:使用=,您将在两个变量中处理相同的File,因此每次写入两者中的任何一个时,流指针都会在两者上更新。使用reopen 可以让您写入其中一个而不修改另一个位置,因此,如果您再写入另一个,您最终将覆盖之前的内容。
当您运行子进程时,区别很重要。
作业:
$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,否则如果脚本或子进程尝试使用这些流,您可能会遇到管道损坏。
【讨论】: