ruby-on-rails - Errno::EACCES 删除文件时(在 Windows 10 上)
问题描述
有许多类似的问题,但没有一个答案对我有用。
我在Windows 10版本2004 (19041.388)上运行Rails 6.0.3.2、Ruby 2.6.6和SQLite3。我按照 Rails 官方网站上的入门指南安装了 Ruby on Rails,并且一切都应该是最新的。
我可以正常删除文件,并且我使用管理员帐户登录 - 不是必须的。
我是 Ruby 和 Rails 的新手,因此将不胜感激。
代码
以下是导致错误的原因:
def destroy
book = Book.find(params[:id])
begin
File.open(book.cover_url, 'w') do |f|
File.delete(f)
end
rescue Errno::ENOENT
end
book.destroy
redirect_to books_path
end
这是做什么的,它首先删除一本书的封面图像,然后从数据库中删除这本书本身。
错误
错误画面:
如果图片未加载,以下是错误消息:
Errno::EACCES in BooksController#destroy
Permission denied @ apply2files - D:/Projects/Web/RoR/ecommerce/app/assets/images/covers/circles_scaling_anim_positioning.png
File.delete(f)
是罪魁祸首。
尝试的解决方案
我能为 Windows 找到的唯一可行的答案是this,它主张添加一个“lib”gem,但它根本不起作用。
我还尝试将文件模式从“w”更改为“wb+”,但这也不起作用。
编辑 2:根据 Dave Newton 在评论中的建议(如果这就是他的意思),我将图像存储目录移到了“app”文件夹之外;到“公共/上传/封面”。它也没有奏效。
编辑 3:我将删除代码完全复制到另一个目录中的新脚本中,并在示例文件上进行了尝试。我得到了同样的错误。换句话说,问题不在于 Rails,而在于 Ruby(或我的操作系统)。
我从终端调用
rm
了文件,效果很好,所以我不知道这是否是文件权限问题。
编辑:我检查了有问题的文件,虽然它仍然存在,但它现在是 0 字节大,所以我认为它被空数据覆盖。然而,应该执行的其余代码destroy
——即数据库中对象的销毁——似乎没有运行,因为对象仍然在那里。
解决方案
与大多数 UNIXy 操作系统(例如 macOS、Linux 或各种 BSD)相比,操作系统强制执行的文件处理在 Windows 上是不同的。
在 UNIXy 操作系统上,文件系统中的文件条目只是指向存储在磁盘上的“真实”文件的指针。还有其他可能的指针,例如文件被进程打开时的文件句柄,或硬链接(即指向完全相同文件的不同文件系统条目)。只要至少有一个指向该文件的有效指针,该文件就存在于磁盘上。
因此,在 UNIXy 系统上,您可以在从进程打开文件时从文件系统中删除(或重命名/移动)文件。文件本身只有在最后一个文件句柄关闭后才会真正被删除。
但是默认情况下,Windows 在这方面更加严格。只要有任何进程在文件上具有文件句柄(即如果任何进程打开了文件),它就不允许删除文件。这解释了为什么当你有文件句柄时不能删除文件
话虽如此,自从 Ruby 2.3.0 以来,您可以在打开文件时设置一个标志,指示 Windows 允许在打开文件时删除(或移动)文件:
# the flags for the normal 'w' mode
file_mode = IO::WRONLY | IO::CREAT | IO::TRUNC
# Add flags to allow deleting (or moving) the opened file
file_mode |= IO::BINARY | IO::SHARE_DELETE
File.open(book.cover_url, mode: file_mode) do |f|
File.delete(f)
end
请注意,该IO::SHARE_DELETE
标志仅适用于以二进制模式(而不是文本模式)打开的文件,在处理此打开的文件时要考虑这一点。在 UNIXy 系统上IO::SHARE_DELETE
被忽略。
有一些可用的各种标志的文档。
最后一点:我假设您的代码是一个缩短的示例,除了删除它之外,您还遗漏了一些实际与打开的文件交互的代码。
如果您只想删除文件,则无需先打开它。只需删除它File.delete(book.cover_url)
。或者,如果您不关心任何错误(例如,如果文件首先不存在,您也可以使用FileUtils.rm_f(book.cover_url)
.
推荐阅读
- javascript - 每天设置代码开始的时间和代码停止的时间,并在第二天从该点继续
- nginx - Nginx 在将上游连接到 Unicorn 时拒绝许可
- javascript - vuex不返回对象
- python-3.x - 如何使用 SSIM 或与“纯 python”或 Pythonista 兼容的类似算法比较两张 PIL.Image JPEG 照片(相同大小)?
- c# - 可以做些什么来防止多人黑客攻击?
- r - R:如何将 x 聚合并分离成多个列?有趣 = 独一无二
- gradle - 查看存储库中是否存在 Gradle 构建中较新版本的工件
- r - 在 R 中使用 ggmap 和 ggplot2 进行映射:(警告消息:1:`panel.margin` 已弃用。2:删除了没有值的行)
- linker - ctype 加载的共享库符号也在 glibc 中定义;如何选择符号?
- git - 如何在修订版中“穿越” git 存储库?