Reputation: 155
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.
Upvotes: 2
Views: 6373
Reputation: 289
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);
}
}
}
Upvotes: 0
Reputation: 16242
// 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...
Upvotes: 2
Reputation: 1
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.
Upvotes: 1