Ruby在哪里跟踪其打开的文件描述符?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (26)

这个问题不是关于如何使用File#close或File#open block语法自动关闭文件。这是一个关于Ruby在运行时存储其打开的文件描述符列表的问题。

实际问题

如果你有一个带有开放描述符的程序,但你无法访问相关的文件或IO对象,那么你如何找到对当前打开的文件描述符的引用?以这个例子:

filename='/tmp/foo'
%x( touch "#{filename}" )
File.open(filename)
filehandle = File.open(filename)

第一个File实例打开,但对象的引用不存储在变量中。第二个实例存储在文件句柄中,我可以使用#inspect或#close轻松访问它。

但是,丢弃的File对象不会消失; 它只是无法以任何明显的方式访问。在对象完成之前,Ruby必须在某个地方跟踪它,在哪里?

提问于
用户回答回答于

TL; DR

所有文件和IO对象都存储在ObjectSpace中。

回答

对象空间类说:

ObjectSpace模块包含许多与垃圾收集工具交互的例程,并允许您用迭代器遍历所有活动对象。

我如何测试的

我在Ruby 1.9.3p194的控制台上测试了这个。

测试非常简单。这个想法是让两个File对象具有不同的对象标识,但只有一个可以通过变量直接访问。另一个是“在某处”。

# Don't save a reference to the first object.
filename='/tmp/foo'
File.open(filename)
filehandle = File.open(filename)

然后我探索了不同的方式,即使我没有使用明确的对象引用,也可以与File对象进行交互。一旦我了解ObjectSpace,这一点非常容易。

# List all open File objects.
ObjectSpace.each_object(File) do |f|
  puts "%s: %d" % [f.path, f.fileno] unless f.closed?
end

# List the "dangling" File object which we didn't store in a variable.
ObjectSpace.each_object(File) do |f|
  unless f.closed?  
    printf "%s: %d\n", f.path, f.fileno unless f === filehandle
  end
end

# Close any dangling File objects. Ignore already-closed files, and leave
# the "accessible" object stored in *filehandle* alone.
ObjectSpace.each_object(File) {|f| f.close unless f === filehandle rescue nil}

结论

可能还有其他的方法可以做到这一点,但是我的方法很适合我。

扫码关注云+社区