我怀疑主要区别在于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/nullFile 对象不使用 ,而是分配给 时 $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