重新打开IO流与只使用新流的区别

4
在Ruby-Docs中,举了这样一个例子:
f1 = File.new("testfile")
f2 = File.new("testfile")
f2.readlines[0]   #=> "This is line one\n"
f2.reopen(f1)     #=> #<File:testfile>
f2.readlines[0]   #=> "This is line one\n"

我的问题是为什么要重新打开f2,而不是使用f2.closef1.readlines[0]?重新打开流与只使用新流相比有哪些优点?

2个回答

1

我之前和一些IRB的开发人员交流过,得到的回复是它主要用于更改$std变量以修改像putsprint这样的方法输出的位置...

$stdout.reopen(File.open('log'))
puts 'hello world'

使用这个的原因而不是...

$stdout = File.open('log')

...这个问题有点不确定。我有一个开发人员说直接赋值与 Ruby 的一些 C 函数不兼容。我对 C 不是很了解,也不能多说什么,但他指向了一些 minitest source 来看看它的使用示例。然而,显然即使源代码也已经从上次开发人员查看时切换到了直接赋值 vs. 重新打开。

总之...从外表看来,IO#reopen可能是无用的,但我很想听听反对意见。

更新

好的,所以我重新阅读了文档,并看到了 reopen 的第二组 opts:

reopen(path, mode_str) → ios

这似乎实际上有些有用,而不是使用reopen(other_IO) → ios选项。


0

我怀疑主要的区别在于使用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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接