简体   繁体   中英

C++ move all files from one directory to another

I have a problem moving data from one directory to another. I want to do as below (bash) but in C++:

mv /testdir/* /testdest/

So it should basically move all files located in /testdir to /testdest . I've already tried rename in C++ but it does not actually move data, it just renames directories.

My current code:

#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])
}

I am executing this as below:

./static-mv /testdir/ /testdest/

Effect of this is rename /testdir/ to /testdest/ (with its content). After this, /testdir/ is no longer available which is not the expected result.

// 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...

You might use nftw(3) to collect all the paths, and then loop on mkdir(2) & rename(2) . nftw uses opendir(3) , readdir(3) , closedir , stat(2) (which you might directly use).

With a recent C++17 implementation you might use <filesystem>

If some other process is writing into subdirectories, you could be in trouble (as mv probably is).

Perhaps running /bin/mv (that file path is standardized by POSIX) in another process could be simpler.

There could be issues if /testdir and /testdest are in different file systems (and mount points), since rename(2) works only in one file system. mv knows how to handle that (in that case, it copy files before deleting the source). Also, some of the sub-directories of /testdir could be mount points, etc..

If both /testdir/ and /testdest/ are in the same file system and there is no mount points under /testdir , you could just loop with opendir , readdir , closedir , skip the . and .. entries, construct for each directory entry the corresponding full source and destination paths, and use rename on these.

Of course, mv is free software, in GNU coreutils , and you might study its source code (it is less simple that what you might believe, since it handles corner cases). You could also use strace(1) to understand which system calls (listed in syscalls(2) ) are involved by some mv command or process.

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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM