【问题标题】:Forbid "rename" to copy a file禁止“重命名”复制文件
【发布时间】:2019-05-15 14:29:18
【问题描述】:

如果newname 指向不同的驱动器,rename 实际上会复制文件(至少在Windows 10 平台上)。

有没有办法避免这种情况?我希望它在这种情况下失败。

假设我想移动 100 GB 的文件。如果可能的话,我想重命名它。如果没有 - 我想使用我自己的复制功能并向用户显示操作的进度。

【问题讨论】:

  • 文件驻留在不同卷中时无法重命名,因为每个卷上的文件目录不同。这就像将西红柿从一个冰箱“重命名”到另一个冰箱,不知何故你必须先转移它。当它是一卷时,重命名只会更改索引。
  • 我知道!我说的是c++重命名函数的实现!请阅读问题。
  • Is there a way to avoid this? - 在调用 rename 之前确定路径是否属于不同的驱动器,如果是,不调用 rename?
  • 是否有跨平台的方法来确定这一点?我认为这不是一项简单的任务。
  • 是卷,不是盘符。即使是 linux,如果要将文件放在不同的卷上,无论挂载点如何,“重命名”仍然会复制+删除。

标签: c++


【解决方案1】:

您可以尝试创建指向新目的地的硬链接。如果失败,则失败。如果成功,则删除原始文件。我验证这适用于 Linux(g++ 8.3.1 和 clang++ 7.0.1)和 Windows(VS2019)上的文件(不是目录),并希望它也适用于大多数其他现代操作系统:es。需要 C++17(或 boost 用于旧编译器)。

#include <filesystem>
#include <iostream>
#include <string_view>
#include <vector>

bool my_rename(const std::string_view from, const std::string_view to,
               std::error_code& ec)
{
    // create hard link
    std::filesystem::create_hard_link(from, to, ec);

    if(ec) return false; // it failed

    // remove the original
    return std::filesystem::remove(from, ec);
}

int cppmain(const std::string_view program, std::vector<std::string_view> args) {
    if(args.size() != 2) {
        std::cerr << "USAGE: " << program << " <source> <target>\n";
        return 1;
    }

    std::error_code ec;

    if(my_rename(args[0], args[1], ec) == false) {
        std::cerr << program << ": " << ec << "\n";
        return 1;
    }

    return 0;
}

int main(int argc, char* argv[]) {
    return cppmain(argv[0], {argv + 1, argv + argc});
}

【讨论】:

  • 我喜欢这个! cppmain 也很好(如果有点复制/分配快乐 - 做一个 string_view 版本!)
  • :-) 谢谢!是的,这不是最有效的程序启动,但之后处理起来很好。将查看string_view 版本。
  • Boom! 加入。 :) 可悲的是,向量仍然分配,但只有一次,而且很便宜,所以耶
  • :-D 很好,但我宁愿将std::string&amp;filesystem::path&amp; 作为my_rename 的参数。没有太多的模糊也许可以解决。
  • 为什么要在不需要时创建std::stringstd::string_view 可以从文字或现有的std::string 创建,因此您不会丢失任何功能,但可能会丢失完全不必要且非常临时的动态分配和字符串复制!这就是他们添加它的原因:) IMO const std::string&amp; 函数 arg 现在应该几乎总是 const std::string_view。例外情况包括在平台上添加“长度”参数(即一个指针+大小,而不是仅仅一个引用,即指针)是禁止的......但这很少见
【解决方案2】:

如果在 Windows 中,您可以使用 MoveFileEx 而不使用 MOVEFILE_COPY_ALLOWED。 您还可以使用GetVolumePathNameW 来确定源和目标是否属于同一卷,因此是否(可能)需要副本。

【讨论】:

  • macOS、Linux、Android 呢?
  • 知道这些操作系统的人可能会发布答案(如果存在)。
  • @AlexanderDyagilev 我不认为你会有这个问题。 rename 的这个“功能”是 Windows 特有的。
  • @PaulSanders 无论操作系统如何,它都是相同的“功能”。这是身体上的限制。
猜你喜欢
  • 2013-06-13
  • 1970-01-01
  • 2016-11-01
  • 2018-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-29
  • 2016-04-09
相关资源
最近更新 更多