Tod*_*obs 21 ruby io file-io file-descriptor filehandle
这个问题不是关于如何使用File #close或File#open block语法自动关闭文件.这是一个关于Ruby在运行时存储其打开文件描述符列表的问题.
如果您的程序具有开放描述符,但您无权访问相关的文件或IO对象,那么如何找到对当前打开的文件描述符的引用?举个例子:
filename='/tmp/foo'
%x( touch "#{filename}" )
File.open(filename)
filehandle = File.open(filename)
Run Code Online (Sandbox Code Playgroud)
第一个File实例被打开,但对象的引用不存储在变量中.第二个实例被存储在文件句柄,其中I可以很容易地与#inspect或#关闭访问它.
但是,丢弃的File对象没有消失; 它只是无法以任何明显的方式访问.在对象完成之前,Ruby必须在某个地方跟踪它...但在哪里?
Tod*_*obs 35
所有File和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)
Run Code Online (Sandbox Code Playgroud)
然后,我研究了可以与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}
Run Code Online (Sandbox Code Playgroud)
可能还有其他方法可以做到这一点,但这是我想出来解决自己的问题的答案.如果您知道更好的方法,请发布另一个答案.世界将是一个更好的地方.