重新打开IO流与仅使用新流

时间:2012-11-28 23:48:10

标签: ruby io

在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"

我的问题是,为什么只能f2f2.close重新开启f1.readlines[0]?使用新流重新打开是否有任何优势?仅使用新流?

2 个答案:

答案 0 :(得分:1)

我在一段时间之前与IRB上的一些开发人员交谈,我得到的回应是它主要用于更改$std变量以修改putsprint等方法的位置输出到......

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

使用此而不是......的原因

$stdout = File.open('log')

......虽然有点在空中。我有一个开发人员说直接分配并不适合某些ruby的C函数。我不太了解C并且不能对此有太多的了解,但是他向我指了一些minitest source来看一个使用它的例子。然而,显然即使是源码已经切换到直接分配与重新开放,因为开发人员最后一次查看它。

总之......从它的外观来看IO#reopen可能毫无用处,但我很乐意听到反对的论点。

<强>更新

好的,所以我重读了文档,发现reopen还有第二组选项:

reopen(path, mode_str) → ios

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

答案 1 :(得分: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 File 对象被分配给 $stderrstderr_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