【问题标题】:C++ move all files from one directory to anotherC ++将所有文件从一个目录移动到另一个目录
【发布时间】:2018-05-14 13:01:31
【问题描述】:

我在将数据从一个目录移动到另一个目录时遇到问题。 我想做如下(bash),但在 C++ 中:

mv /testdir/* /testdest/

所以它应该基本上将位于/testdir 的所有文件移动到/testdest。 我已经在 C++ 中尝试过rename,但它实际上并没有移动数据,它只是重命名目录。

我当前的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <unistd.h>
#include <dirent.h>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <string>
#include <sys/stat.h>
#include <syslog.h>
#include <fstream>

using namespace std;

int main( int argc, char *argv[] )
{
  rename (argv[1], argv[2])
}

我执行如下:

./static-mv /testdir/ /testdest/

这样做的效果是将/testdir/ 重命名为/testdest/(及其内容)。 在此之后,/testdir/ 不再可用,这不是预期的结果。

【问题讨论】:

  • 您必须编写一个循环,这也不是 bash 中的单个操作。
  • mv 非常重要,因为它可以处理大量选项。我建议查看std::filesystem::renamedirectory_iterator
  • 提示:mv /testdir/* /testdest/ 扩展为参数 mv /testdir/A testdir\B testdir\C testdest
  • 所以....如果我想移动所有文件,我实际上需要一个一个地执行此操作吗? (循环中?)
  • mv 如果文件位于同一文件系统中,则仅更改目录条目,但如果跨越边界则必须移动数据。

标签: c++ linux file


【解决方案1】:

您可以使用nftw(3) 收集所有路径,然后在mkdir(2)rename(2) 上循环。 nftw 使用 opendir(3)readdir(3)closedirstat(2)(你可以直接使用)。

对于最近的 C++17 实现,您可能会使用 &lt;filesystem&gt;

如果某些其他进程正在写入子目录,您可能会遇到麻烦(mv 可能是这样)。

也许在另一个进程中运行/bin/mv(该文件路径由 POSIX 标准化)可能更简单。

如果/testdir/testdest不同文件系统(和挂载点)中可能会出现问题,因为rename(2)只能在一个文件系统中工作。 mv 知道如何处理(在这种情况下,它会在删除源之前复制文件)。此外,/testdir 的一些子目录可能是挂载点等。

如果/testdir//testdest/ 都在同一个文件系统中,并且/testdir 下没有挂载点,则可以循环使用opendirreaddirclosedir,跳过@987654348 @ 和.. 条目,为每个目录条目构造对应的完整源和目标路径,并在这些上使用rename

当然,mv 是免费软件,在GNU coreutils 中,你可能会研究它的源代码(它不像你想象的那么简单,因为它处理极端情况)。您还可以使用strace(1) 了解某些mv 命令或进程涉及哪些system calls(在syscalls(2) 中列出)。

【讨论】:

    【解决方案2】:
    // static-mv.cpp
    #include<experimental/filesystem>
    #include<cassert>
    #include<iostream>
    
    int main(int argc, char* argv[]){
        assert(argc >= 3);
        namespace fs = std::experimental::filesystem;
        for(fs::path p : fs::directory_iterator(argv[1])){
            std::cout << p << " -> " << argv[2]/p.filename() << std::endl;
            fs::rename(p, argv[2]/p.filename());
        }
    }
    

    $ c++ -std=c++11 static-mv.cpp -o static-mv -lstdc++fs

    $ mkdir dir1; cd dir1; touch file.a; touch file.b; cd ..; ls dir1/

    file.a  file.b
    

    $ mkdir dir2;

    $ ./static-mv dir1 dir2

    "dir1/file.a" -> "dir2/file.a"
    "dir1/file.b" -> "dir2/file.b"
    

    $ ls dir2/

    file.a  file.b
    

    $ success!

    bash: success!: command not found...
    

    【讨论】:

    • 自 C++17 起已弃用,出现以下错误 #ifndef _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING #error The &lt;experimental/filesystem&gt; header providing std::experimental::filesystem is deprecated by Microsoft \ and will be REMOVED. It is superseded by the C++17 &lt;filesystem&gt; header providing std::filesystem. \ You can define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING to acknowledge that you have received this warning. #endif // _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
    • @ShubhamJain,想更新答案吗?此外,您正在使用 Microsoft 进行编译,这不太可能适用于这个 linux 问题(使用了 linux 标签)。
    【解决方案3】:
    void move(char const *sorc, char const *dst, bool createRoot = true) {
        namespace fs = std::experimental::filesystem;
    
        if (createRoot)
            fs::create_directory(dst);
    
        for(fs::path p: fs::directory_iterator(sorc)){
            fs::path destFile = dst/p.filename();
    
            if (fs::is_directory(p)) {
                fs::create_directory(destFile);
                move(p.string().c_str(), destFile.string().c_str(), false);
            } else {
                //std::cout << "updated " << p.string().c_str() << std::endl;
                fs::rename(p, destFile);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-20
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-26
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      相关资源
      最近更新 更多