Dir.chdir(File.dirname(__FILE__)) 抛出 Errno::ENOENT

Dir.chdir(File.dirname(__FILE__)) throws Errno::ENOENT

我得到了一个在里面使用 Dir.chdir(File.dirname(__FILE__)) 的方法。我正在使用它,这样我就可以从任何地方 运行 ruby 文件而不会出现此错误:No such file or directory @ rb_sysopen - 'filename' (Errno::ENOENT).

第一次使用该方法没问题,第二次使用就报错了。请参阅下面的方法和确切错误。

def meth(string)
  Dir.chdir(File.dirname(__FILE__))
  hash = JSON.parse(File.read("file.json"))
  # do something with hash and string
  # return some value
end

meth("first string")   # this returns what is expected
meth("second string")  # this second usage of the method throws the error

精确定位我使用的行的错误示例Dir.chdir(File.dirname(__FILE__)):

dir/decoder.rb:44:in `chdir': No such file or directory @ dir_s_chdir - lib (Errno::ENOENT)

不确定 OS 是否在这里起作用,我使用的是 11.2.3 版本的 m1 BigSur。

你的问题似乎是 __FILE__ 是一个类似 dir/decoder.rb 的相对路径,并且该路径在第一次使用 Dir.chdir 后变得无效,因为该命令改变了工作整个 Ruby 过程的目录。我认为解决方案是在你的 decoder.rb 文件中做这样的事情:

DecoderDir = File.realpath(File.dirname(__FILE__))

def meth        
  Dir.chdir(DecoderDir)
  # ...
end

我猜想 Ruby 解释器第一次处理文件时,已经足够早了 __FILE__ 中的相对路径仍然指向正确的位置。所以,那个时候,我们生成一个绝对路径,以备后用。

顺便说一下,一个行为良好的库不应该 运行 Dir.chdir 因为它会影响整个 Ruby 过程中所有相对路径的使用。我几乎只 运行 Dir.chdir 一次,我 运行 它靠近我的顶级脚本的开头。如果你正在制作一个可重用的库,你可能想做这样的事情来计算你想打开的文件的绝对路径:

DecoderJson = File.join(DecoderDir, 'file.json')