3

所以我想做的是将文件名传递给方法并检查文件是否已关闭。我正在努力做的是从文件名中获取文件对象而不实际打开文件。

def file_is_closed(file_name)
  file = # The method I am looking for
  file.closed?
end

我必须填写评论部分。我尝试使用 YAML 模块中的 load_file 方法,但我认为这给出了文件的内容而不是实际文件。

我在 File 模块中找不到要调用的方法。有没有我不知道的方法?

4

2 回答 2

1

File#closed?返回该特定 File 对象是否已关闭,因此没有任何方法可以使您当前尝试的解决方案起作用:

f1 = File.new("test.file")
f2 = File.new("test.file")
f1.close
f1.closed? # => true # Even though f2 still has the same file open

如果可能,最好保留您正在使用的 File 对象,以便询问它是否已关闭。

如果您真的想知道您当前的 Ruby 进程是否为特定路径打开了任何 File 对象,这样的事情感觉很hack-ish但应该主要工作:

def file_is_closed?(file_name)
  ObjectSpace.each_object(File) do |f|
    if File.absolute_path(f) == File.absolute_path(file_name) && !f.closed?
      return false
    end
  end

  true
end

我不支持很好地处理极端情况,但总的来说它似乎对我有用:

f1 = File.new("test.file")
f2 = File.new("test.file")
file_is_closed?("test.file") # => false
f1.close
file_is_closed?("test.file") # => false
f2.close
file_is_closed?("test.file") # => true

如果你想知道是否有任何进程打开了文件,我认为你需要求助于外部的东西,比如lsof.

于 2013-06-07T03:49:07.593 回答
0

对于那些您不再能够访问 Ruby 中的原始文件对象的情况(例如,在 fork + exec 之后),/proc/pid/fd 中提供了一个打开文件描述符列表。那里的每个文件都以文件描述符编号命名,并且是指向打开的文件、管道或套接字的符号链接:

# Returns hash in form fd => filename
def open_file_descriptors
  Hash[
  Dir.glob( File.join( '/proc', Process.pid.to_s, 'fd', '*' ) ).
    map { |fn| [File.basename(fn).to_i, File.readlink(fn)] rescue [nil, nil] }.
    delete_if { |fd, fn| fd.nil? or fd < 3 }
  ]
end

# Return IO object for the named file, or nil if it's not open
def io_for_path(path)
  fd, fn = open_file_descriptors.find {|k,v| path === v}
  fd.nil? ? nil : IO.for_fd(fd)
end

# close an open file
file = io_for_path('/my/open/file')
file.close unless file.nil?

open_file_descriptors方法解析 fd 目录并返回像 {3 => '/my/open/file'} 这样的哈希。然后,获取所需文件的文件描述符编号是一件简单的事情,并让 Ruby 为它生成一个 IO 对象for_fd

当然,这假设您使用的是 Linux。

于 2013-06-07T13:04:09.530 回答