You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Dir.mktmpdir在Windows下无法删除临时目录的问题?

根因分析

这个报错是Windows系统的文件占用机制导致的,和目录本身的权限配置无关:

  • Linux/macOS系统下,即使文件被进程打开,只要权限足够依然可以执行删除操作;但Windows会强制锁定被进程持有句柄的文件/目录,只要句柄没释放,删除操作会直接抛出权限拒绝错误
  • 代码里执行File.write、File.delete后,Ruby的文件IO句柄不会被即时回收,依赖GC机制异步释放。等Dir.mktmpdir块执行到末尾自动清理临时目录时,残留的句柄还没被系统释放,就会触发这个rmdir报错
  • 另外原代码里的断言写法本身有问题:assert_equal需要传入「期望值」「实际值」两个参数,只传一个参数会触发参数错误,判断文件存在应该用assert File.exist?(f)
修复方案

按优先级选择对应方案即可:

  • 最小改动修复:在块末尾、临时目录被自动删除前,强制触发GC回收未释放的文件句柄
class TestFoo < Minitest::Test
  def test_basic
    Dir.mktmpdir 'test' do |dir|
      f = File.join(dir, 'foo.txt')
      File.write(f, "Hello")
      assert File.exist?(f) # 修正原断言的参数错误
      File.delete(f)
      GC.start # 强制回收IO句柄,解决Windows下句柄延迟释放问题
    end
  end
end
  • CI环境适配:从报错路径看是在GitHub Actions的Windows runner上跑测试,这类环境默认开启Windows Defender实时扫描,新建的临时文件会被杀毒软件短暂锁定,光触发GC不够,需要给目录删除逻辑加重试:
# 给FileUtils的删除逻辑加重试,遇到占用就等100ms再试,最多重试3次
original_remove_entry = FileUtils.method(:remove_entry)
FileUtils.define_singleton_method(:remove_entry) do |path, force = false|
  remaining_retries = 3
  begin
    original_remove_entry.call(path, force)
  rescue Errno::EACCES
    remaining_retries -= 1
    sleep 0.1
    retry if remaining_retries > 0
    raise
  end
end
  • 源头减少句柄残留:所有文件操作优先用块形式调用,块退出时会立刻关闭文件句柄,比直接调用File.write更稳妥:
# 替换原来的File.write调用
File.open(f, 'w') { |io| io.write("Hello") }
避坑提示
  • 尽量不要把临时目录放在同步盘、杀毒软件重点监控的目录下,这类程序会频繁扫描新建文件,非常容易触发句柄占用
  • 不要依赖Ruby的GC自动回收IO资源,涉及文件、网络连接的资源,优先用块形式调用确保即时释放。

内容的提问来源于stack exchange,提问作者yegor256

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 19:21:27