我怀疑主要区别在于reopen 的新流不仅适用于$std... 变量的后续使用,还适用于之前被赋值的变量$std... 变量。这可能是好是坏,取决于您的情况。
这个 irb 会话表明,使用reopen,在流更改之前分配的变量将获取新更改的流。请注意,fileno 对于任何一个变量都不会改变,并且两个变量都不会产生输出:
> $stderr.fileno
=> 2
> stderr_copy = $stderr
=> #<IO:<STDERR>>
> stderr_copy.fileno
=> 2
> $stderr.reopen(File.open('/dev/null', 'w'))
=> #<File:/dev/null>
> stderr_copy.fileno
=> 2
> $stderr.fileno
=> 2
> $stderr.puts 'foo'
=> nil
> stderr_copy.puts 'foo'
=> nil
相比之下,当不使用reopen 而是将新打开的/dev/null 文件对象分配给 $stderr 时,stderr_copy 将保留其原始输出流。只有$stderr 得到新的fileno,stderr_copy 仍然产生输出:
> $stderr.fileno
=> 2
> stderr_copy = $stderr
=> #<IO:<STDERR>>
> stderr_copy.fileno
=> 2
> $stderr = File.open('/dev/null', 'w')
=> #<File:/dev/null>
> $stderr.fileno
=> 10
> stderr_copy.fileno
=> 2
> $stderr.puts 'foo'
=> nil
> stderr_copy.puts 'foo'
foo
=> nil
如果你想使用reopen,但又想保存一份原始输出流的副本,你可以使用dup:
> stderr_dup = $stderr.dup
=> #<IO:<STDERR>>
> stderr_dup.fileno
=> 10
> $stderr.reopen(File.open('/dev/null', 'w'))
=> #<File:/dev/null>
> $stderr.fileno
=> 2
> stderr_dup.puts 'foo'
foo
=> nil
> $stderr.puts 'foo'
=> nil