Ruby 在哪里跟踪其打开的文件描述符?
Posted
技术标签:
【中文标题】Ruby 在哪里跟踪其打开的文件描述符?【英文标题】:Where does Ruby keep track of its open file descriptors? 【发布时间】:2012-06-10 22:20:37 【问题描述】:这个问题不是关于什么
这个问题不是关于如何使用 File#close 或 File#open 块语法自动关闭文件。这是一个关于 Ruby 在运行时将其打开文件描述符列表存储在哪里的问题。
实际问题
如果您有一个带有打开描述符的程序,但您无权访问相关的 File 或 IO 对象,您如何找到对当前打开的文件描述符的引用?举个例子:
filename='/tmp/foo'
%x( touch "#filename" )
File.open(filename)
filehandle = File.open(filename)
第一个 File 实例已打开,但对该对象的引用未存储在变量中。第二个实例存储在 filehandle 中,我可以使用 #inspect 或 #close 轻松访问它。
但是,丢弃的 File 对象并没有消失;它只是无法以任何明显的方式访问。在对象最终确定之前,Ruby 必须在某个地方跟踪它……但是在哪里呢?
【问题讨论】:
【参考方案1】:TL;博士
所有 File 和 IO 对象都存储在 ObjectSpace 中。
回答
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
结论
可能还有其他方法可以做到这一点,但这是我想出的解决方案。如果您知道更好的方法,请发布另一个答案。世界会因为它而变得更美好。
【讨论】:
对于任何关心任何打开的文件描述符而不仅仅是磁盘上的实际文件的人,您可以将上面的代码修改为:ObjectSpace.each_object(IO) |f| puts f unless f.closed?
我想知道(Ruby)子进程(即在 fork 之后)是否会看到每个(继承的)打开文件描述符的 File 对象。
非常有帮助,谢谢。为了详细说明 Liron 的观点,在使用这种方法时,我认为应该考虑包含 或排除 的 IO 子类(例如,你想要 stdin、stdout、stderr 吗?)。此外,尽管对某些人来说可能很明显,但此表达式将返回所有打开的 IO:ObjectSpace.each_object(IO).reject(&:closed?)
这在 Ruby 3.0.1 的 irb 中为我返回了以下内容:[#<IO:<STDERR>>, #<IO:<STDOUT>>, #<IO:<STDIN>>, #<IO:fd 1>, #<IO:fd 0>].
以上是关于Ruby 在哪里跟踪其打开的文件描述符?的主要内容,如果未能解决你的问题,请参考以下文章