Create a directory if it doesn't exist - c++

In my app I want to copy a file to the other hard disk so this is my code:
#include <windows.h>
using namespace std;
int main(int argc, char* argv[] )
{
string Input = "C:\\Emploi NAm.docx";
string CopiedFile = "Emploi NAm.docx";
string OutputFolder = "D:\\test";
CopyFile(Input.c_str(), string(OutputFolder+CopiedFile).c_str(), TRUE);
return 0;
}
so after executing this, it shows me in the D:HDD a file testEmploi NAm.docx
but I want him to create the test folder if it doesn't exist.
I want to do that without using the Boost library.

Use the WINAPI CreateDirectory() function to create a folder.
You can use this function without checking if the directory already exists as it will fail but GetLastError() will return ERROR_ALREADY_EXISTS:
if (CreateDirectory(OutputFolder.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// CopyFile(...)
}
else
{
// Failed to create directory.
}
The code for constructing the target file is incorrect:
string(OutputFolder+CopiedFile).c_str()
this would produce "D:\testEmploi Nam.docx": there is a missing path separator between the directory and the filename. Example fix:
string(OutputFolder+"\\"+CopiedFile).c_str()

#include <experimental/filesystem> // or #include <filesystem> for C++17 and up
namespace fs = std::experimental::filesystem;
if (!fs::is_directory("src") || !fs::exists("src")) { // Check if src folder exists
fs::create_directory("src"); // create src folder
}

Probably the easiest and most efficient way is to use boost and the boost::filesystem functions. This way you can build a directory simply and ensure that it is platform independent.
const char* path = _filePath.c_str();
boost::filesystem::path dir(path);
if(boost::filesystem::create_directory(dir))
{
std::cerr<< "Directory Created: "<<_filePath<<std::endl;
}
boost::filesystem::create_directory - documentation

Here is the simple way to create a folder.......
#include <windows.h>
#include <stdio.h>
void CreateFolder(const char * path)
{
if(!CreateDirectory(path ,NULL))
{
return;
}
}
CreateFolder("C:\\folder_name\\")
This above code works well for me.

_mkdir will also do the job.
_mkdir("D:\\test");
https://msdn.microsoft.com/en-us/library/2fkk4dzw.aspx

OpenCV Specific
Opencv supports filesystem, probably through its dependency Boost.
#include <opencv2/core/utils/filesystem.hpp>
cv::utils::fs::createDirectory(outputDir);

Since c++17, you can easily do this cross-platform with:
#include <filesystem>
int main() {
auto created_new_directory
= std::filesystem::create_directory("directory_name");
if (not created_new_directory) {
// Either creation failed or the directory was already present.
}
}
Note, that this version is very useful, if you need to know, whether the directory is actually newly created.
And I find the documentation on cppreference slightly difficult to understand on this point: If the directory is already present, this function returns false.
This means, you can more or less atomically create a new directory with this method.

Use CreateDirectory (char *DirName, SECURITY_ATTRIBUTES Attribs);
If the function succeeds it returns non-zero otherwise NULL.

You can use cstdlib
Although- http://www.cplusplus.com/articles/j3wTURfi/
#include <cstdlib>
const int dir= system("mkdir -p foo");
if (dir< 0)
{
return;
}
you can also check if the directory exists already by using
#include <dirent.h>

This works in GCC:
Taken from:
Creating a new directory in C
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct stat st = {0};
if (stat("/some/directory", &st) == -1) {
mkdir("/some/directory", 0700);
}

Related

Create Directory and Navigate into Directory c++

I have successfully made a directory in AppData Folder, but i want to navigate into that folder using C++ How do i go about it.
My code looks like this
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
//printf("Hello world!\n");
char *name = getenv("USERNAME");
char info[1500];
const int bufferSize = MAX_PATH;
sprintf(info,"C:\\Users\\%s\\AppData\\Local\\BizMail", name);
_mkdir(info);
getchar();
return 0;
}
Use chdir() function it works on both POSIX and Windows.
Here is the man page
You can also use SetCurrentDirectory() function. Refer here and here is the sample program.

find and move files in C++

I'm new to C++ and I've just read <C++ Primer> 4ed. Now I want to implement a little program to help me manage some mp3 files in my computer.
I have a .txt file which includes all the names(part of the names actually) of the files which I want to move(not copy) to a new folder(in the same column). For example, "word" and "file" in the .txt and I want to move all the .mp3 files whose filename contain "word" or "file" to a new folder. Hope my discription is clear, Opps..
I know how to read the strings in .txt into a set<string> and traverse it, but I have no idea how to search and move a file in a folder. I just want to know what else should I learn so that I can implement this function. I read C++ Primer and still I can't do much thing, that's really sad...
To move a file in C++, you do not have to use external libraries like Boost.Filesystem, but you can use standard functionality.
There is the new filesystem API, which has a rename function:
#include <iostream>
#include <filesystem>
int main() {
try {
std::filesystem::rename("from.txt", "to.txt");
} catch (std::filesystem::filesystem_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}
The drawback is to compile it, you need a recent C++17 compiler. (I tested it on gcc 8.0.1, and I also needed to link against -lstdc++fs).
But what should work on any C++ compiler today, is the old C API, which also provides rename (cstdio):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cerrno>
int main() {
if(std::rename("from.txt", "to.txt") < 0) {
std::cout << strerror(errno) << '\n';
}
return 0;
}
But note that in both cases, the rename will fail if the source and destination files are not on the same filesystem. Then you will see an error like this:
filesystem error: cannot rename: Invalid cross-device link [from.txt] [/tmp/to.txt]
In that case, you can only make a copy and then remove the original file:
#include <fstream>
#include <iostream>
#include <ios>
#include <cstdio>
int main() {
std::ifstream in("from.txt", std::ios::in | std::ios::binary);
std::ofstream out("to.txt", std::ios::out | std::ios::binary);
out << in.rdbuf();
std::remove("from.txt");
}
Or with the new API:
#include <iostream>
#include <filesystem>
int main()
{
try {
std::filesystem::copy("from.txt", "to.txt");
std::filesystem::remove("from.txt");
} catch (std::filesystem::filesystem_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}
Use rename() function to move a file
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char oldname[] = "C:\\Users\\file_old.txt";
char newname[] = "C:\\Users\\New Folder\\file_new.txt";
/* Deletes the file if exists */
if (rename(oldname, newname) != 0)
perror("Error moving file");
else
cout << "File moved successfully";
return 0;
}
The only way for this to work only using std would be to read the file completely using a std::ifstream and then write it to the new location with a std::ofstream. This will however not remove the old file from disk. So basically you create a copy of the file. Its also much slower than a real move.
The optimal solution is to use OS specific APIs like win32 which e.g provide a MoveFile() function. Poco provides an platform independent abstraction of such APIs. See: http://www.appinf.com/docs/poco/Poco.File.html
Another way to move a file in Windows is using the MoveFile function as it is shown in the following code.
std::wstring oldPath = L"C:\\Users\\user1\\Desktop\\example\\text.txt";
std::wstring newPath = L"C:\\Users\\user1\\Desktop\\example1\\text.txt";
bool result = MoveFile(newPath.c_str(), oldPath.c_str());
if (result)
printf("File was moved!");
else
printf("File wasn't moved!");
under Windows run system call with batch commands:
system("move *text*.mp3 new_folder/");
system("move *word*.mp3 new_folder/");
Under Unix same with shell syntax.

Check if file exists in C++

I'm very very new to C++.
In my current project I already included
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
and I just need to do a quick check in the very beginning of my main() to see if a required dll exists in the directory of my program.
So what would be the best way for me to do that?
So, assuming it's OK to simply check that the file with the right name EXISTS in the same directory:
#include <fstream>
...
void check_if_dll_exists()
{
std::ifstream dllfile(".\\myname.dll", std::ios::binary);
if (!dllfile)
{
... DLL doesn't exist...
}
}
If you want to know that it's ACTUALLY a real DLL (rather than someone opening a command prompt and doing type NUL: > myname.dll to create an empty file), you can use:
HMODULE dll = LoadLibrary(".\\myname.dll");
if (!dll)
{
... dll doesn't exist or isn't a real dll....
}
else
{
FreeLibrary(dll);
}
There are plenty ways you can achieve that, but using boost library is always a good way.
#include <boost/filesystem.hpp>
using boost::filesystem;
if (!exists("lib.dll")) {
std::cout << "dll does not exists." << std::endl;
}

How can I enumerate all the file in a directory in vfs c or c++? [duplicate]

This question already has answers here:
How do you get a directory listing in C?
(9 answers)
Recursive function for listing all files in sub directories
(10 answers)
Closed 10 years ago.
I need to enumerate all the file in a folder and then navigate to the subfolder and do the same (recursion? sure).
Ideally the algorithm should work in the same way on linux & macos
DISCLAIMER: I have asked a similar question on POSIX: I'm now aware of VFS but I'm puzzled to use VFS for enumerate dir. Any suggestion ? Should I open a dir as file ? The only way is to use a library cross platform like qt ?
UPDATE: so no VFS way to work on directory? "*V*irtual *F*ile *S*ystem provides a single API for accessing various different file systems" but no way to enumerate directory.
The "readdir" etc solution will do the trick on any type of *NIX ? And on windows nothing better than the huge MingW lib? or partial impletion working on only some win like:
https://github.com/xbmc/xbmc/blob/master/tools/TexturePacker/Win32/dirent.c
The BOOST seem to be a really cool solution but it's complex and academic. thnks in any case
LAST UPDATE:
I have found some more doc and now everything is a lot more clear.
This question is a duplicate!
opendir() and readdir() are the solution to enumerate and browse directory on linux. As shown on my example is quite easy to map them on windows (but the incoerent windowz fs make everything strange) and ntfw() is even more useful.
VFS (the virtual file switch) is a kernel feature that resolves this problem by creating an abstraction layer for file-system operations. closed doc here: linux programming interface
thnks!
You want to look at nftw. Here's an example that just recursively prints the contents of a directory in C (Untested):
#define _XOPEN_SOURCE 500
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ftw.h>
int
print( const char *path, const struct stat *s, int flag, struct FTW *f )
{
puts( path );
return 0;
}
int
main( int argc, char **argv )
{
while( *++argv ) {
if( nftw( *argv, print, 1024, FTW_DEPTH )) {
perror( *argv );
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Here is how I do it using Boost.Filesystem:
#include "boost/filesystem.hpp"
#include <iostream>
int main () {
for ( boost::filesystem::recursive_directory_iterator end, dir("./");
dir != end; ++dir ) {
// std::cout << *dir << "\n"; // full path
std::cout << dir->path().filename() << "\n"; // just last bit
}
}
Or, more succinctly:
#include "boost/filesystem.hpp"
#include <iostream>
#include <iterator>
#include <algorithm>
int main () {
std::copy(
boost::filesystem::recursive_directory_iterator("./"),
boost::filesystem::recursive_directory_iterator(),
std::ostream_iterator<boost::filesystem::directory_entry>(std::cout, "\n"));
}
Unix/Linux/Windows all have versions of readdir(). You can use it to get what the file system knows about files.

Invalid use of incomplete type 'DIR'

I'm trying to compile this code, which works fine on Windows, on Linux (Code::Blocks):
/* Edit: Includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <...>
/**/
/* === */
/* Function code */
DIR *dp;
dirent *ep;
string name_parent;
dp = opendir(somepath);
name_parent = dp->dd_name; //error
/**/
Since path names on Windows are not case sensitive, I can read a user input like "c://program files" and get the "correct" path "C:\Program Files*" (except for the asterisk - or "F://" -> "F:*"). I also use this variable to get a directory listing with absolute path values, since ep->d_name (after some readdir() of course) returns a path relative to somepath.
On Linux, I get a compiler error (for "dp->dd_name"):
error: invalid use of incomplete type 'DIR'
Did I forget something?
Or is there a logical error?
Edit: I've added the includes (that I'm already using) above.
/* Edit: Includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <...>
/**/
/* === */
/* Function code */
DIR *dp;
dirent *ep;
string name_parent;
dp = opendir(somepath);
ep = readdir(dp);
name_parent = ep->d_name;
/**/
The variable d_name exists in the struct dirent which gives the name of the directory
You didn't declare the type of DIR! On Posix systems, you would have said,
#include <sys/types.h>
#include <dirent.h>
However, on Windows, you don't have these features. Instead, you could use the Windows API filesystem functions.
yes. you missed including header files.
dirent.h
The internal structure of a DIR is unspecified, so you should never rely on it and expect your code to be portable.
The glib source for Windows says this about DIR:
/*
* This is an internal data structure. Good programmers will not use it
* except as an argument to one of the functions below.
Apparently, the type DIR is not defined at the point you're trying to use it. Maybe you forgot an #include?
It is not about to forget including some headers or definition now I've faced this problem but not error it was warning.
My files.h;
class Files
{
public:
explicit Files(const char *p_path = 0);
~Files();
/* .... */
private:
std::string path;
}
My files.cpp;
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h> // I added this line with #Kerrek SB's advice but nothing changed
#include <dirent.h>
#include <files.h>
static DIR *p_dir = NULL;
static struct dirent *p_ent = NULL;
Files::Files(const char *p_path)
{
if (p_path == NULL)
{
std::cerr << "PATH is NULL" << std::endl;
exit(EXIT_FAILURE);
}
path = p_path;
p_dir = opendir(p_path);
if (p_dir == NULL)
{
std::cerr << "Cannot open " << path << std::endl;
exit(EXIT_FAILURE);
}
}
Files::~Files()
{
if (p_dir)
{
/* Here is my warning occuring in this line and the definition
line p_dir 'static DIR *p_dir = NULL' */
delete p_dir; // After changing this line with 'free(p_dir);' warnings gone.
p_dir = NULL;
}
}
The warning at the definition line (static DIR *p_dir = NULL;) is 'p_dir' has incomplete type and the warning at the delete line (delete p_dir;) is possible problem detected in invocation of delete operator: [-Wdelete-incomplete].
After changing the delete p_dir; with free(p_dir); the both warnings are gone.
I don't know it's exact reason but it sounds like DIR * type acting like void *. I'm just taking a wild guess.
Hope this helps.