在Windows上是否可以进行原子文件重命名(覆盖)?

4uqofj5v  于 2023-08-07  发布在  Windows
关注(0)|答案(8)|浏览(239)

在POSIX系统上,rename(2)提供了原子重命名操作,包括覆盖目标文件(如果它存在且权限允许的话)。
有没有办法在Windows上获得相同的语义?我知道Vista和Server 2008上的MoveFileTransacted(),但我需要它来支持Win2k及以上版本。
这里的关键词是“原子”。该解决方案必须不能以任何方式失败,从而使操作处于不一致的状态。
我看到很多人说这在win32上是不可能的,但我问你,真的吗?
如果可能的话,请提供可靠的引用。

yzxexxkh

yzxexxkh2#

Win32不保证原子文件Meta数据操作。我会提供一个引用,但没有-事实上,没有书面或文件的保证意味着同样多。
你必须编写你自己的例程来支持它。这很不幸,但是你不能指望win32提供这种级别的服务-它根本不是为它设计的。

nimxete2

nimxete23#

在Windows Vista和Windows Server 2008中添加了一个原子移动函数- MoveFileTransacted()
不幸的是,这对旧版本的Windows没有帮助。
Interesting article here on MSDN的数据。

h5qlskok

h5qlskok4#

从Windows 10 1607开始,NTFS支持原子取代重命名操作。为此,调用NtSetInformationFile(..., FileRenameInformationEx, ...)并指定FILE_RENAME_POSIX_SEMANTICS标志。
或者在Win32中调用SetFileInformationByHandle(..., FileRenameInfoEx, ...)并指定FILE_RENAME_FLAG_POSIX_SEMANTICS标志。

omhiaaxx

omhiaaxx5#

你仍然可以在Windows上调用rename(),尽管我想如果不知道你正在使用的文件系统,你就不能保证你想要的--例如,如果你使用FAT,就不能保证。
但是,您可以使用MoveFileEx并使用MOVEFILE_REPLACE_EXISTING和MOVEFILE_WRITE_THROUGH选项。后者在MSDN中有这样的描述:
设置此值可确保在函数返回之前,作为复制和删除操作执行的移动将刷新到磁盘。刷新发生在复制操作结束时。
我知道这不一定与重命名操作相同,但我认为这可能是您将获得的最佳保证-如果它对文件移动这样做,它应该用于更简单的重命名。

nhaq1z21

nhaq1z216#

MSDN文档避免明确说明哪些API是原子函数,哪些不是,但Niall道格拉斯在他的Cppcon 2015 talk中指出,唯一的原子函数是
SetFileInformationByHandle
FILE_RENAME_INFO.ReplaceIfExists设置为true。它从Windows Vista / 2008 Server开始可用。
Niall是一个非常复杂的LLFIO library的作者,并且是文件系统竞争条件方面的Maven,所以我相信如果你正在编写一个原子性至关重要的算法,最好是安全的,即使ReplaceFile的描述中没有任何内容表明它不是原子的,也要使用建议的函数。

xqkwcwgp

xqkwcwgp7#

有很多答案,但不是我所期待的...我有这样的理解(也许是错误的),MoveFile * 可以是 * 原子的,只要正确的星星对齐,使用标志,并且源文件系统与目标文件系统相同。否则,操作将返回到[Copy->Delete]文件。
考虑到这一点;我也理解MoveFile -当它是原子的时-只是设置文件信息,这也可以在这里完成:setfileinfobyhandle的数据。
有人做了一个名为“Racing the Filesystem”的演讲,对这个问题进行了更深入的讨论。(大约2/3的人在谈论原子重命名)

xytpbqjk

xytpbqjk8#

std::rename,从C++17std::filesystem::rename开始。未指定如果目标存在std::rename会发生什么:
如果new_filename存在,则行为是实现定义的。
但是,需要POSIX rename来原子地替换现有文件:
对于常规文件,此rename()函数等效于ISO C标准定义的文件。在此包含它扩展了该定义,以包括对目录的操作,并指定当新参数命名已存在的文件时的行为。该规范要求函数的动作是原子的。
幸运的是,std::filesystem::rename要求它的行为就像POSIX一样:
将old_p标识的文件系统对象移动或重命名为new_p,就像通过POSIX重命名一样
然而,当我尝试调试时,VS2019(截至2020年3月)实现的std::filesystem::rename似乎只是调用MoveFileEx,在某些情况下它不是原子的。因此,当它实现中的所有bug都被修复后,我们可能会看到可移植的atomic std::filesystem::rename

相关问题