I am making use of opendir() as below to access a directory.
DIR *dp;
if((dp = opendir(dir.c_str())) == NULL) {
cout << "Error(" << errno << ") opening " << dir << endl;
return errno;
}
However, I keep getting the error below, even though the directory exists.
Error(2) opening /path/to/folder/
I am able to get a list of file names when I do ls /path/to/folder
Be aware that /path/to/folder is different from /path/to/folder/
errno value 2 means ENOENT (it's an abbreviaton for Error NO ENTry) that is "Directory does not exist, or name is an empty string".
How do you define dir in your code?
std::string dir = "/path/to/folder/";
DIR* dp = opendir(dir.c_str());
if (dp == NULL)
{
std::cout << "Error(" << errno << ") opening " << dir << std::endl;
perror("opendir");
return errno;
}
closedir(dp);
Update #1:
Try to call you shell script:
main.sh folder/ foldername
Where main.sh contains:
#!/bin/sh
path="$1$2"
echo "$path"
ls -l "$path"
Related
I'm trying to make a program that moves a file (like file.txt) specified by the user to a directory that he also specifies. I tried using the move() function, however I don't quite understand it yet, so I tried with the rename() function and used this site's code as help.
I've worked with the rename() function and moved a file like this:
char oldDir[] = "C:\\Users\\MyName\\file.txt";
char newDir[] = "C:\\Users\\MyName\\New folder\\file.txt";
if (rename(oldDir, newDir) != 0)
perror("Error moving file");
else
cout << "File moved successfully";
And that worked perfectly, if I typed in the directory correctly. The thing is that I would like to tell the user to type in the directory of a file to move to another directory, so I tried this:
char oldDir[] = " ";
char newDir[] = " ";
cout << "Type file directory: "; cin >> oldDir;
cout << "Type file directory to move to: "; cin >> newDir;
if (rename(oldDir, newDir) != 0)
perror("Error moving file");
else
cout << "File moved successfully";
But, when typing in the console the oldDir path like: C:\\Users\\MyName\\file.txt, I always get the error:
Error moving file no such file or directory
It returns before I can even type the newDir path. Of course the file.txt is in C:\Users\MyName.
What could be the problem? I tried to remove the " " from the oldDir and newDir variables, but then I get another error:
incomplete type is not allowed
What am I doing wrong?
First off, don't double up on the slashes when typing them in at the command prompt at runtime, if that is what you are doing. Escaping slashes only applies to string literals in code, not runtime data.
That said, you are not allocating enough memory to hold the user's input. When initialized with " ", your oldDir[] and newDir[] arrays are each only 2 chars in size. When you drop the " ", the compiler no longer knows how large to make the array, since you are not telling it which size to use.
You need to handle the arrays more like this instead:
char oldDir[MAX_PATH] = "";
char newDir[MAX_PATH] = "";
std::cout << "Type file directory: ";
cin.getline(oldDir, MAX_PATH); // paths can contain spaces!
std::cout << "Type file directory to move to: ";
cin.getline(newDir, MAX_PATH); // paths can contain spaces!
if (rename(oldDir, newDir) != 0)
perror("Error moving file");
else
std::cout << "File moved successfully" << std::endl;
However, you really should be using std::string instead:
std::string oldDir, newDir;
std::cout << "Type file directory: ";
std::getline(cin, oldDir); // paths can contain spaces!
std::cout << "Type file directory to move to: ";
std::getline(cin, newDir); // paths can contain spaces!
if (rename(oldDir.c_str(), newDir.c_str()) != 0)
perror("Error moving file");
else
std::cout << "File moved successfully" << std::endl;
If you are using C++17 or later, consider using std::filesystem::rename() instead of ::rename():
#include <filesystem>
std::string oldDir, newDir;
std::cout << "Type file directory: ";
std::getline(cin, oldDir); // paths can contain spaces!
std::cout << "Type file directory to move to: ";
getline(cin, newDir); // paths can contain spaces!
std::error_code err;
std::filesystem::rename(oldDir, newDir, err);
if (err)
std::cerr << "Error moving file: " << err.message() << endl;
else
std::cout << "File moved successfully" << std::endl;
I'm using visual studio 2017, running with the c++17 ISO Standard(not boost) set to be able to use <filesystem>. I'm running into a wall though because everytime I run, whether in debug or release, file_copy() gives me the error access denied. I've checked the other bits of my code and the only thing that isn't working is file_copy(). Does anyone know why I'm getting this error and how to fix it? I'm the administrative account on my PC.
std::vector<std::string> findAndCopyFiles()
{
std::vector<std::string> fileNames;
std::error_code errCode;
errCode.clear();
fs::current_path("C:\\Users\\kenny\\Desktop\\Engine", errCode);
std::cout << errCode.message() << std::endl; errCode.clear();
fs::path pa = fs::current_path();
pa += "\\TEMP";
std::cout << pa.string() << std::endl;
if (fs::create_directory(pa, errCode))//Create directory for copying all files)
{
std::cout << "Directory created successfully" << std::endl;
std::cout << errCode.message() << std::endl; errCode.clear();
}
fs::path tempDir(pa);
fs::path currentDirectory = fs::current_path();
fs::recursive_directory_iterator dirIter(currentDirectory);
for (auto &p : dirIter)
{
if (p.path().extension() == ".cpp" || p.path().extension() == ".h")
{
//std::string fileContents = getFileContents(p.path().string());
std::string fileName = p.path().stem().string();
if (!fs::copy_file(p.path(), tempDir, fs::copy_options::overwrite_existing, errCode))
{
std::cout << "failed to copy file: " << fileName << " from " << p.path().string() << " to " << tempDir.string() <<std::endl;
}
std::cout << errCode.message() << std::endl; errCode.clear();
//ensures file is a cpp file before adding it to list of fileNames
if (p.path().extension().string() == ".cpp")
{
auto it = std::find(fileNames.begin(), fileNames.end(), fileName); //seaches TEMP folder for file
if (it == fileNames.end())
{//if file was not found in vector of registered file names, add it
fileNames.push_back(fileName);
}
}
}
}
std::cout << "All files found. " << fileNames.size() << " files were found" << std::endl;
return fileNames;
}
As per the comments. You were trying to overwrite a directory with a regular file. From the documentation [trimmed]
o Otherwise, if the destination file already exists...
o Report an error if any of the following is true:
o to and from are the same as determined by equivalent(from, to);
o to is not a regular file as determined by !is_regular_file(to)
So you need to append the filename to the destination directory path using the `std::filesystem::operator/ overload (untested)...
if (!fs::copy_file(p.path(), tempDir / p.filename(), fs::copy_options::overwrite_existing, errCode))
So this is my code but I cant prevent it from printing out: . .. and it counts them as a file. I couldnt understand why.
The output is:
.
1files.
..
2files.
course3.txt
3files.
course2.txt
4files.
course1.txt
5files.
But there are only 3 files... It should say 3 files instead it counts that . .. and i dont know its meaning.
int folderO(){
DIR *dir;
struct dirent *ent;
int nFiles=0;
if ((dir = opendir ("sampleFolder")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
std::cout << ent->d_name << std::endl;
nFiles++;
std::cout << nFiles << "files." << std::endl;
}
closedir (dir);
}
else {
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
}
. and .. are meta directories, current directory and parent directory respectively.
What you have found is that subdirectories are being printed along with files. And so are symlinks and other "weird" Unix-y stuff. Couple ways to filter those out if you don't want them printed:
If your system supports d_type in the dirent structure, check that d_type == DT_FILE before printing. (GNU page on dirent listing possible d_types)
if (ent->d_type == DT_FILE)
{
std::cout << ent->d_name << std::endl;
nFiles++;
std::cout << nFiles << "files." << std::endl;
}
if d_type is not supported, stat the file name and check that it is a file st_mode == S_ISREG.
struct stat statresult;
if (stat(ent->d_name, &statresult) == 0)
{
if (statresult.st_mode == S_ISREG)
{
std::cout << ent->d_name << std::endl;
nFiles++;
std::cout << nFiles << "files." << std::endl;
}
}
And of course there is the dumb-simple strcmp-based if statement, but this will list all other subdirectories.
Crap. Sorry. C++. that last line should be "And of course there is the dumb-simple std::string operator==-based if statement, but this will list all other subdirectories."
. is current directory inode (technically, a hardlink), .. is parent directory.
These are there for navigation. They're directories, perhaps you can ignore them if they are directories?
A Google search would have revealed that these are special folder names with these meanings:
. the current directory
.. the parent directory
Any tutorial on iterating a directory shows you how to filter these out with a simple "if" statement.
I'm reading all file names from a certain directory using this function:
void getdir(std::string dir, std::list<std::string>& files)
{
DIR *dp;
struct dirent *dirp;
if((dp = opendir(dir.c_str())) == NULL)
{
std::cout<< "Error: path " << dir << " onbekend!\n";
}
else
{
while ((dirp = readdir(dp)) != NULL)
{
files.push_back(std::string(dirp->d_name));
}
closedir(dp);
}
}
When I print them out, I get '.' or '..' too with the filenames. But the file '.' or '..' is not in the directory.
I'm using ubuntu 12.04 :)
. is current directory, and .. is parent directory, you will find them in every directory.
I am using system() to run some Unix commands from my application with code like the following:
std::stringstream command;
command << "rm -rf /some/directory";
int rmResult = system(command.str().c_str());
if (rmResult != 0) {
clog << "Error: Failed to remove old output directory '" << command.str()
<< "' (" << errno << ") " << strerror(errno) << ".\n";
throw;
}
However, while rmResult is zero and the rm works, I get this error in the console:
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
What am I doing wrong, and how can I get this message to go away?
Apparently, this was due to having a directory that is now gone on my pushd stack, even though it was not the current working directory. Cleaning out my stack of the now gone directory, caused the messages to go away.