scan directory to find and open the file - c++

I want to make a program that lets user enter drive name/folder(C:\ or f:\folder\) and a file name (test.exe) then program searches that file in the given drive or folder and opens the file.I managed to do the function that opens the file but cannot figure out how to search the file pass the location of file found to open it. Can anyone help me?

You can use boost::file_system. Here is documentation: http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
EDIT: after some time, I've got that my ansver were sligtly out of topic. To check if file exists you can use special boost::filesystem function.
bool exists(const path& p);
/EDIT
And directory iterator example: http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/tutorial.html#Directory-iteration
It that example used std::copy, but you need filenames. So you can do something like this.
#include <boost/filesystem.hpp>
namespace bfs = boost::filesystem;
std::string dirPath = "."; // target directory path
boost::filesystem::directory_iterator itt(bfs::path(dirPath)); // iterator for dir entries
for ( ; itt != boost::filesystem::directory_iterator(); itt++)
{
const boost::filesystem::path & curP = itt->path();
if (boost::filesystem::is_regular_file(curP)) // check for not-a-directory-or-something-but-file
{
std::string filename = curP.string(); // here it is - filename in a directory
// do some stuff
}
}
If you are not expirienced with boost - building it can be complicated.
You can obtain prebuilded boost binaries for your compiller and platform at boost.teeks99.com
Also, if you cant use boost for some reason, there is platform specific ways of iterating a directory, but I dont know on which platform you are, so I cant provide you an example.

Try this:
char com[50]="ls ";
char path[50]="F:\\folder\\";
char file[50]="test.exe";
strcat(com,path);
strcat(com,file);
if (!system(com)) // system returns the return value of the command executed
cout<<"file not present\n";
else
{
cout<<"file is present\n";
strcat(path,file);
FILE* f = fopen(path,"r");
//do your file operations here
}

Related

ifstream won't find file even though it's in the same directory

I've got a method to read a vector of bools from a file:
std::vector<bool> OPCConnector::getAlarmVector() {
std::vector<bool> data;
std::ifstream DataFile(filepath);
if (DataFile) {
bool value;
while (DataFile >> value) {
data.push_back(value);
std::cout << value;
}
}
return data;
}
The filepath variable is an object property that is assigned through the constructor:
OPCConnector::OPCConnector(std::string fpth) {
filepath = fpth;
}
And in the main() function, the constructor is called:
std::vector<bool> activations;
std::string filepath = "alarmes.txt";
OPCConnector opcc = OPCConnector(filepath);
activations = opcc.getAlarmVector();
Now, I've checked what the folder of the executable is via GetModuleFileNameA(), and I made sure that the file is in the same directory and has the same name (also, I made sure that the extension isn't part of the file name, like "alarmes.txt.txt").
I debugged the first method getAlarmVector() and it never gets past the if (DataFile) condition, as if it won't find file.
I run the code using Visual Studio 2019, and nothing happens. The vector remains empty. Error is No such file or directory.
Default working directory is $(ProjectDir) and it's exactly where my file is.
Edit: I've also tried using both relative and absolute paths, none work.
Edit 2: I've also checked the directory using GetCurrentDirectory() and copied the .txt file there too, and it isn't working.
SOLUTION: Strangely enough, I deleted the file and created it again with the same name, and it worked. Thanks for the answers.
My guess: your current working directory isn't what you think it is, especially if you're running from an IDE. I know of several IDEs where the current working directory is some build directory (it varies by IDE) unless you specifically change it.
I'm fairly sure Visual Studio is one such IDE.
Here's a tiny example program I wrote;
$ cat Foo.cpp
#include <iostream>
#include <fstream>
int main(int, char **) {
std::ifstream file { "Foo.cpp" };
if (file) {
std::cout << "File opened.\n";
}
else {
std::cout << "File not opened.\n";
}
}
Compile and run it:
$ g++ --std=c++17 Foo.cpp -o Foo && Foo
File opened.
Current folder and folder-of-exe-file are different things (sometimes). Try to specify full name of file (with disk, all folders, etc.).
You can check errors of file open operation by calling
if (!DataFile) { ... }
The std::filesystem library can help you resolve file and path related issues.
#include <filesystem>
// (in some function)
std::filesystem::path filepath = "alarmes.txt";
if ( !exists(filepath) )
{
std::cout << "File path " << filepath << " at absolute location "
<< absolute(filepath) << " does not exist\n";
}
See it on Compiler Explorer
You can get an error code (and get a description of error in internet) if you use C-function fopen. If open is failed, you get the nullptr as result of fopen and errno will contain code of error.

How to run a c++ program multiple times with different input files?

I'm new to C++ and writing my master thesis and would really appreciate any help I can get!
I have a program that reads a txt file, then does a bunch of calculations, and returns a new txt file. The thing is that I want to run this program for 100+ different input files. Now I have to change the name of the input file in the code, but I would like to have it run for all the input files in my folder by itself.
I am using Visual Studio, but with little C++ experience.
Thanks :)
See this snippet. Since you are using MSCV, you need to enable MFC in configuration for this console application. Also add #include "afx.h" in #include "stdafx.h" where CFileFind is defined. PopulateFromFolder() should auto load the files into the vector files.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void PopulateFromFolder(string path, vector<string>& files)
{
CFileFind finder;
CString fileName;
fileName.Format(L"%s*.*", CString(path.c_str()));
BOOL bOk = finder.FindFile(fileName);
while (bOk)
{
bOk = finder.FindNextFile();
if (finder.IsDots())
{
continue;
}
if (!finder.IsDirectory())
{
CString strFileName = finder.GetFileName();
files.push_back(CStringA(strFileName).GetString());
}
}
finder.Close();
}
int main()
{
vector<string> files;
string path = "D:\\MyFolder\\";
PopulateFromFolder(path, files);
auto a = path + files[0];
int i = 0;
while (i< files.size()-1)
{
cout << "processing " << files[i + 1] << endl;
ifstream fs(path+files[i++]);
if (fs.is_open())
{
//do something
}
fs.close();
}
return 0;
}
Output:
Using bash you can run them using:
$ for file in /Data/*.txt; do /path/your_program $file; done
You can define format for your input files names and put then into some directory. For example,
Input1.txt
Input2.txt
...
Input111.txt
Then use some kind of for loop:
for(int i = 1; i <= 111; ++i)
{
ifstream file("Input" + std::to_string(i) + ".txt");
if (file.is_open())
Operate(file);
}
If you don't know the exact number of files, you can check whether the file was openen by is_open() method. This way files with some numbers can be absent. You just loop for some max possible input file id.
This was a solution which doesn't require any dependencies. But if you don't mind it, you actually may consider Boost.Filesystem. Here is an example.
You can try to use std::experimental::filesystem (http://en.cppreference.com/w/cpp/experimental/fs). I guess that directory_iterator from this library can be useful for you - it allows you to iterate over all files in a given directory. Have a look at the example provided in the documentation: http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator.
However, you have to make sure that you are compiling your code with a new standard (C++ 17).
Another way is to make for example a separate file containing a list of the names of all files that you want to work on. Then, you can read this list and for every file do what you need.

c++ ofstream write_to_log.open (" relative path + array");

I want the line below to write a new file using the content given in the array
but into a new folder named logs:
char log_file_name[100]; /* this array contains the name of a new file */
ofstream write_to_log;
write_to_log.open (relative path, log_file_name , fstream::app);
How do I get it working ?
You can use CreateDirectory for creating folders with VC++ in Windows.
#include <windows.h>
#include <string>
#include <fstream>
using namespace std;
int main() {
string path = "C:\\users\\folder";
CreateDirectory(path.c_str(), NULL);
char log_file_name[100] = "log.txt";
path += '\\';
path += log_file_name;
ofstream write_to_log(path.c_str(), fstream::app);
return 0;
}
The NULL refers to a security attributes structure that you may have to create. More details at MSDN here and in this answer.
You can save your self a lot of potential trouble and replace char log_file_name[100]; with std::string log_file_name; The benefits of string are many, the most important here are they resize and they make appending really easy. The string does everything a char array does and a whole lot of extras. In virtually all cases, you should chose a string over a char array.
string path;
string log_file_name;
With the path and the file name as strings
path += "\\" + log_file_name
ofstream write_to_log(path, fstream::app);
if (write_to_log)
{ // file is open and looks writable (have to start writing to be sure)
// do stuff. Or not. It's a free country.
}
else
{ // file didn't open
// Handle error
}
All done and the file, if it exists and is writable, is open and ready to go. Always check the state of a stream when you use it. SO is littered with questions from people who didn't and got confused by the result.
On older compilers you may have to change the create and open line slightly:
ofstream write_to_log(path.c_str(), fstream::app);

read only .txt files from directory which has subfolders too

I am trying to read only .txt files from directory.
I am not using arrays.
I am using opendir() to open my directory.
d->d_name lists all my files and also subfolders.
I want to read only .txt but not the subfolders.
please help me.
Thanks
Can you not use FindFirstFile and FindNextFile for this?
Well, something like:
call opendir() to open the directory
in a loop, call readdir to read each entry
for each entry, examine the name to see if the last 4 characters are ".txt"
if they are, do something
at the end, call closedir to close the directory
You can use the stat() function to determine the type of file your struct dirent represents.
struct stat sb;
int rc = stat(filename, &sb);
// error handling if stat failed
if (S_ISREG(sb.st_mode)) {
// it's a regular file, process it
} else {
// it's not a regular file, skip it
}
Read the man pages for details. Also take care that the filename in d_name does not contain the directory part. If you're in a different directory than what you opendir'd, you'll need to prepend the directory name (and a directory separator if required).
For a C++ alternative, please see boost::filesystem.
You could try put the filenames into a simple structure (string array or vector for example), then pass a reference to that structure to a function that prunes names that don't use the .txt extension
in the function, look at each filename (a for loop would be handy), and use the find function in the String library to see if the last four characters are == to .txt. You can reset the position of to start searching the string to string_name.length - 4 so that you're only comparing the last few characters.
Cplusplus.com is a great reference for things like the String library: http://www.cplusplus.com/reference/string/string/find/
Assuming you are on a Linux/Posix system, you can use scandir(...). You can find the details on the manual page, but in short, you have to provide a filter function that takes a dirent pointer as argument, and returns non-zero if the entry is to be included (in your case, you would check for the name ending in .txt, and possibly the file type in the dirent struct).
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
int main(int argc, char *argv[])
{
DIR *dir;
struct dirent *entry;
int pos;
if (argc < 2)
{
printf("Usage: %s <directory>\n", argv[0]);
return 1;
}
if ((dir = opendir(argv[1])) == NULL)
{
perror("opendir");
return 1;
}
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type != DT_REG)
continue;
pos = strlen(entry->d_name) - 4;
if (! strcmp(&entry->d_name[pos], ".txt"))
{
printf("%s\n", entry->d_name);
}
}
if (closedir(dir) == -1)
{
perror("closedir");
return 1;
}
return 0;
}

Open file by its full path in C++

I want the user to give me the full path where the file exists and not just the file name. How do I open the file this way?
Is it something like this:
ifstream file;
file.open("C:/Demo.txt", ios::in);
This doesn't seem to work.
Normally one uses the backslash character as the path separator in Windows. So:
ifstream file;
file.open("C:\\Demo.txt", ios::in);
Keep in mind that when written in C++ source code, you must use the double backslash because the backslash character itself means something special inside double quoted strings. So the above refers to the file C:\Demo.txt.
You can use a full path with the fstream classes. The folowing code attempts to open the file demo.txt in the root of the C: drive. Note that as this is an input operation, the file must already exist.
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream ifs( "c:/demo.txt" ); // note no mode needed
if ( ! ifs.is_open() ) {
cout <<" Failed to open" << endl;
}
else {
cout <<"Opened OK" << endl;
}
}
What does this code produce on your system?
The code seems working to me. I think the same with #Iothar.
Check to see if you include the required headers, to compile. If it is compiled, check to see if there is such a file, and everything, names etc, matches, and also check to see that you have a right to read the file.
To make a cross check, check if you can open it with fopen..
FILE *f = fopen("C:/Demo.txt", "r");
if (f)
printf("fopen success\n");
For those who are getting the path dynamicly... e.g. drag&drop:
Some main constructions get drag&dropped file with double quotes like:
"C:\MyPath\MyFile.txt"
Quick and nice solution is to use this function to remove chars from string:
void removeCharsFromString( string &str, char* charsToRemove ) {
for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) {
str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() );
}
}
string myAbsolutepath; //fill with your absolute path
removeCharsFromString( myAbsolutepath, "\"" );
myAbsolutepath now contains just C:\MyPath\MyFile.txt
The function needs these libraries: <iostream> <algorithm> <cstring>.
The function was based on this answer.
Working Fiddle: http://ideone.com/XOROjq
A different take on this question, which might help someone:
I came here because I was debugging in Visual Studio on Windows, and I got confused about all this / vs \\ discussion (it really should not matter in most cases).
For me, the problem was: the "current directory" was not set to what I wanted in Visual Studio. It defaults to the directory of the executable (depending on how you set up your project).
Change it via: Right-click the solution -> Properties -> Working Directory
I only mention it because the question seems Windows-centric, which generally also means VisualStudio-centric, which tells me this hint might be relevant (: