I am an absolute newbie to C++ and have only started to program with it 3 days ago.
I am trying to do the folliwng:
traverse a directory for X.X files (typically .), and for each file, do the following:
Search within the file for a string (findFirst) and then search until another string (findLast) - The files will be HTML format.
In this selection, I want to perform several tasks (yet to write) - but they will be the following:
One of the strings will be the Filename I want to write to. - so extract this field and create an outputfile with this name
Some of the lines will be manufacturer part numbers - extract these and format the output file accordingly
most of it will be description of product. Again - this will be in an HTML construct - so extract this and format the output file.
So far, I have managed to get working the traverse directory, and selecting the start and finish keywords - using some help from the internet.
My problem is here
processFiles(inputFileName, "testing", "finish");
I need the inputFileName to be the name of the traversed filename.
All the examples I have found simply print the filename using cout
I need to pass this into the processFiles function.
Can someone tell me what i need to use? i have tried it->c_Str() and other variations of (*it) and .at, .begin etc
my non printing example is below:
// Chomp.cpp : Defines the entry point for the console application.
//
#include <stdafx.h>
#include <windows.h>
#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <cctype>
#include <algorithm>
#include <vector>
#include <stack>
//std::ifstream inFile ( "c:/temp/input.txt" ) ;
std::ofstream outFile( "c:/temp/output.txt") ;
using namespace std;
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
void openFiles()
{
if (!(outFile.is_open()))
{
printf ("Could not Create Output file\n");
exit(0);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
bool ListFiles(wstring path, wstring mask, vector<wstring>& files)
{
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty())
{
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
return false;
do
{
if (wcscmp(ffd.cFileName, L".") != 0 && wcscmp(ffd.cFileName, L"..") != 0)
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
directories.push(path + L"\\" + ffd.cFileName);
else
files.push_back(path + L"\\" + ffd.cFileName);
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES)
{
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
void processFiles(const wchar_t *inFileName, std::string findFirst,std::string findLast )
{
/*
std::string findFirst = "testing" ;
std::string findLast = "finish" ;
*/
std::string inputLine ;
int lineNum = 0 ;
char buffer[2048];
size_t found = 0;
std::ifstream inFile;
inFile.open (inFileName); // Open The file
if (inFile.is_open())
{
while( std::getline( inFile, inputLine ))
{
++lineNum ;
// printf ("Line len = %d\n ", inputLine.length());
if( (found = inputLine.find(findFirst)) != std::string::npos )
{
std::cout << "###Line " << lineNum << " At Position [ " << found << " ]\n" ;
sprintf_s(buffer, 2048, "[%-5.5d] %s\n", lineNum, inputLine.c_str());
outFile << buffer ;
bool foundLast = 0;
while( std::getline( inFile, inputLine ))
{
++lineNum ;
sprintf_s(buffer, 2048, "[%-5.5d] %s\n", lineNum, inputLine.c_str());
if( (found = inputLine.find(findLast)) != std::string::npos )
{
outFile << buffer ;
break; // Found last string - so stop after printing last line
}
else
outFile << buffer ;
}
}
else
{
// std::cout << "=>" << inputLine << '\n' ;
}
}
}
else
{
printf ("Cant open file \n");
exit(0);
}
inFile.close() ; // Close The file
}
/////////////////////////////////////////////////////////////////////////////////////////////
/// M A I N
/////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
std::ifstream inFile ;
int startLine = 0;
int endLine = 0;
int lineSize = 0;
char buffer[512];
vector<wstring> files; // For Parsing Directory structure
openFiles();
// Start The Recursive parsing of Directory Structure
if (ListFiles(L"C:\\temp", L"*.*", files))
{
for (vector<wstring>::iterator it = files.begin(); it != files.end(); ++it)
{
printf ("Filename1 is %s\n", it->c_str());
printf ("Filename2 is %s\n", files.begin());
outFile << "\n------------------------------\n";
//outFile << it << endl;
wcout << it->c_str() << endl;
outFile << "\n------------------------------\n";
const wchar_t *inputFileName = it->c_str();
// processFiles(inputFileName, "testing", "finish");
// getchar();
}
}
outFile.close();
getchar();
}
Make your processFile accept a wstring, viz:
void processFiles(wstring inFileName, std::string findFirst,std::string findLast )
{
// Make the necessary changes so that you use a wstring for inFileName
}
Call it from main() using:
processFiles(*it, "testing", "finish");
You need to change processFile to use a wifstream instead of a ifstream and you should change all of your narrow strings to use wide strings (or vice versa). Narrow strings and wide strings are not compatible with each other and in order to use one with the other a conversion function must be used such as mbstowcs.
Edit:
You can find an example that should compile here.
Related
I've written this code, which it get the repository and look for the files within. it aims to create binary files for each file found so as to write some data inside it later. However, the code is not running as expected. and the binary file are not created this the issue.
the directory has two images, and the output I get is as follows :
Creating bin files
C:\repo\1.bin
Error: failed to create file
Press <RETURN> to close this window...
I really do not know where I miss it. Any advice I'd be glad.
#include <vector>
#include <string>
#include <iostream> // for standard I/O
#include <string> // for strings
#include <iomanip> // for controlling float print precision
#include <sstream> // string to number conversion
#include <fstream>
using namespace std;
void getDir(string d, vector<string> & f)
{
FILE* pipe = NULL;
string pCmd = "dir /B /S " + string(d);
char buf[256];
if( NULL == (pipe = _popen(pCmd.c_str(),"rt")))
{
cout<<"Error"<<endl;
return;
}
while (!feof(pipe))
{
if(fgets(buf,256,pipe) != NULL)
{
f.push_back(string(buf));
}
}
_pclose(pipe);
}
void replaceExt(string& s, const string& newExt) {
string::size_type i = s.rfind('.', s.length());
if (i != string::npos) {
s.replace(i+1, newExt.length(), newExt);
}
}
using namespace std;
int main(int argc, char* argv[])
{
vector<string> files;
string path = "C:\\repo";
getDir(path, files);
vector<string>::const_iterator it = files.begin();
cout<<"Creating bin files "<<endl;
ofstream myOfstream;
while( it != files.end())
{
string fileName = (string) *it;
replaceExt(fileName, "bin");
cout << fileName << '\n';
std::stringstream ss;
ss << fileName << "" ;
myOfstream.open(ss.str(), fstream::binary);
if ( !myOfstream )
{
std::cerr << "Error: failed to create file " << '\n';
break;
}
myOfstream.close();
it++;
}
return 0;
}
First I have to say, if you directory you are looking for doesn't exists or is empty, the program gets locked, it would be nice to have that fixed if making a bigger program.
Then, for your case, I don't see whars the point of that stringstream, so I tried removing that, and changing it by a normal string, removing the last \n character you get from reading the filenames:
cout << fileName << '\n';
string ss = fileName.substr(0, fileName.size() - 1);
myOfstream.open(ss.c_str(), fstream::binary);
if (!myOfstream)
{
hope it helps
I found the issue bro, after debugging ;D
the problem is in the "newline", the string fileName has a "\n" at the end that's whats rise your error. Thus you have to erase it, I ve used this statement fileName.erase(std::remove(fileName.begin(), fileName.end(), '\n'), fileName.end());
and I included algorithm lib.
the working code is as follows :
#include <vector>
#include <string>
#include <iostream> // for standard I/O
#include <string> // for strings
#include <iomanip> // for controlling float print precision
#include <sstream> // string to number conversion
#include <fstream>
#include <algorithm>
using namespace std;
void getDir(string d, vector<string> & f)
{
FILE* pipe = NULL;
string pCmd = "dir /B /S " + string(d);
char buf[256];
if( NULL == (pipe = _popen(pCmd.c_str(),"rt")))
{
cout<<"Error"<<endl;
return;
}
while (!feof(pipe))
{
if(fgets(buf,256,pipe) != NULL)
{
f.push_back(string(buf));
}
}
_pclose(pipe);
}
void replaceExt(string& s, const string& newExt) {
string::size_type i = s.rfind('.', s.length());
if (i != string::npos) {
s.replace(i+1, newExt.length(), newExt);
}
}
using namespace std;
int main(int argc, char* argv[])
{
vector<string> files;
string path = "C:\\repo";
getDir(path, files);
vector<string>::const_iterator it = files.begin();
cout<<"Creating bin files "<<endl;
ofstream myOfstream;
while( it != files.end())
{
string fileName = (string) *it;
replaceExt(fileName, "bin");
cout << fileName << '\n';
fileName.erase(std::remove(fileName.begin(), fileName.end(), '\n'), fileName.end());
std::stringstream ss;
ss << fileName << "" ;
myOfstream.open(ss.str(), fstream::binary);
if ( !myOfstream )
{
std::cerr << "Error: failed to create file " << '\n';
break;
}
myOfstream.close();
it++;
}
return 0;
}
I want to copy the content o directory(tmp1) to another directory(tmp2). tmp1 may contain files and others directories. I want to copy the content of tmp1 (including the mode) using C/C++. If tmp1 contains a tree of directories I want to copy them recursively.
What is the simplest solution?
I found a solution to open the directory and read every entry and copy it with cp command. Any simpler solutions?
I recommend using std::filesystem (merged to ISO C++ as of C++17!)
Shamelessly copied from http://en.cppreference.com/w/cpp/filesystem/copy:
std::filesystem::copy("/dir1", "/dir3", std::filesystem::copy_options::recursive);
Read more about it:
https://gcc.gnu.org/onlinedocs/gcc-6.1.0/libstdc++/api/a01832.html
experimental::filesystem linker error
Recently I had the same need, so I have developed the next chunk of code in order to solve the problem. I hope it helps to another people in the same situation.
#include <iostream>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <windows.h>
using namespace std;
bool is_dir(const char* path);
void copyFile_(string inDir, string outDir);
void copyDir_(const char *inputDir, string outDir);
int main()
{
string srcDir = "C:\\testDirectory";
string destDir = "C:\\destDir";
copyDir_(srcDir.c_str(), destDir);
return 0;
}
void copyDir_(const char *inputDir, string outDir)
{
DIR *pDIR;
struct dirent *entry;
string tmpStr, tmpStrPath, outStrPath, inputDir_str = inputDir;
if (is_dir(inputDir) == false)
{
cout << "This is not a folder " << endl;
return;
}
if( pDIR = opendir(inputDir_str.c_str()) )
{
while(entry = readdir(pDIR)) // get folders and files names
{
tmpStr = entry->d_name;
if( strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 )
{
tmpStrPath = inputDir_str;
tmpStrPath.append( "\\" );
tmpStrPath.append( tmpStr );
cout << entry->d_name;
if (is_dir(tmpStrPath.c_str()))
{
cout << "--> It's a folder" << "\n";
// Create Folder on the destination path
outStrPath = outDir;
outStrPath.append( "\\" );
outStrPath.append( tmpStr );
mkdir(outStrPath.c_str());
copyDir_(tmpStrPath.c_str(), outStrPath);
}
else
{
cout << "--> It's a file" << "\n";
// copy file on the destination path
outStrPath = outDir;
outStrPath.append( "\\" );
outStrPath.append( tmpStr );
copyFile_(tmpStrPath.c_str(), outStrPath.c_str());
}
}
}
closedir(pDIR);
}
}
bool is_dir(const char* path)
{
struct stat buf;
stat(path, &buf);
return S_ISDIR(buf.st_mode);
}
void copyFile_(string inDir, string outDir)
{
CopyFile(inDir.c_str(), outDir.c_str(), 1);
DWORD Error = GetLastError();
}
hello I want to read a file located in a subfolder of my program.I succeeded to read the file in the mainfolder of my program.But i cant read the file in a subfolder.
I tried to add a new string named subdir = "/*/" and do like this to get the subfolder but the program refused to take the new paths with my string subdir.Does anyone has a clue on how to do it ? I am running out of ideas lool.
char resulta[ MAX_PATH];
DWORD flicksa = GetModuleFileName(NULL,resulta,MAX_PATH);
_chdir(std::string(resulta,GetCurrentDirectory(flicksa,resulta)).c_str());
std::string path = "/Users/Aymann/Desktop/arraysort/2CPP-REVISIONS/Supcount/";
std::string searchPattern = "/*.cpp";
std::string fullSearchPath = path + searchPattern;
WIN32_FIND_DATA FindData;
HANDLE hFind;
hFind = FindFirstFile( fullSearchPath.c_str(), &FindData );
if( hFind == INVALID_HANDLE_VALUE )
{
cout << "Error searching directory\n";
return -1;
}
do
{
char c;
string filePath = path + FindData.cFileName;
ifstream in( filePath.c_str() );
if( in.is_open() )
{in.get(c);
while (in) {
while (in && c != '\n') {
in.get(c);
}
_rowcount = _rowcount + 1;
in.get(c);
} // do stuff with the file here
}
else
{
cout << "Problem opening file " << FindData.cFileName << "\n";
}
}
while( FindNextFile(hFind, &FindData) > 0 );
if( GetLastError() != ERROR_NO_MORE_FILES )
{
cout << "Something went wrong during searching\n";
}
You cannot pass wildcards to fstream.
Solution: descent folders, open files.
See glob(), opendir(), readdir(), closedir().
I am trying to store the name of all txt files in a directory in a string and print them out. I need to count the number of txt files in the directory and then print the names. The part of counting is working, but I can't seem to get the name working. I have found some examples but they don't work in visual studio which is what I'm using.
Here is my code.
int main() {
bool x = true;
int i = 0;
wchar_t* file = L"../Menu/Circuitos/*.txt";
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile(file, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE) {
i++;
while ((x = FindNextFile(hFind, &FindFileData)) == TRUE) {
i++;
}
}
cout << "number of files " << i << endl;
return 0;
}
FindFirstFile already has the first valid handle. If you immediately call FindNextFile then the first handle is lost. The file count in your example would be wrong.
Use do-while loop istead.
Also, the handle obtained from FindFirstFile must be closed with FindClose
HANDLE hFind;
hFind = FindFirstFile(file, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
wcout << FindFileData.cFileName << "\n";
i++;
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
cout << "number of files " << i << endl;
Use std::vector and std::wstring to store the items
#include <string>
#include <vector>
...
std::vector<std::wstring> vs;
HANDLE hFind;
hFind = FindFirstFile(file, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
vs.push_back(FindFileData.cFileName);
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
std::cout << "count:" << vs.size() << "\n";
for (auto item : vs)
std::wcout << item << "\n";
For some older compilers auto may not be available, use this instead
for (int i = 0; i < vs.size(); i++)
std::wcout << vs[i] << "\n";
Note, Windows API works with c-strings. In many cases you have to use .c_str() to obtain character array. For example:
if (vs.size())
{
std::wstring str = vs[0];
MessageBox(0, str.c_str(), 0, 0);
}
Here is a portable version using the new ISO Standard Filesystem Library TS (technical specification) for those with compilers that support it:
#include <vector>
#include <iostream>
#include <algorithm>
#include <experimental/filesystem>
// for readability
namespace fs = std::experimental::filesystem;
/**
* Function object to test directory entries
* for a specific file extension.
*/
struct file_extension_is
{
std::string ext;
file_extension_is(std::string const& ext): ext(ext) {}
bool operator()(fs::directory_entry const& entry) const
{
return entry.path().extension() == ext;
}
};
int main(int, char* argv[])
{
try
{
// directory supplied on the command line if present
// else current directory
fs::path dir = argv[1] ? argv[1] : ".";
// place to store the results
std::vector<fs::directory_entry> entries;
// copy directory entries that have file extension ".txt"
// to the results
fs::directory_iterator di(dir);
fs::directory_iterator end;
std::copy_if(di, end, std::back_inserter(entries),
file_extension_is(".txt"));
// print it all out
std::cout << "Number of files: " << entries.size() << '\n';
for(auto const& entry: entries)
std::cout << entry.path().string() << '\n';
}
catch(std::exception const& e)
{
std::cerr << e.what() << '\n';
}
catch(...)
{
std::cerr << "Unknown exception." << '\n';
}
}
How can I automatically open and read the content of a file within a given directory from a C++ application without knowing the file's name?
For example (a rough description of the program):
#include iomanip
#include dirent.h
#include fstream
#include iostream
#include stdlib.h
using namespace std;
int main()
{
DIR* dir;
struct dirent* entry;
dir=opendir("C:\\Users\\Toshiba\\Desktop\\links\\");
printf("Directory contents: ");
for(int i=0; i<3; i++)
{
entry=readdir(dir);
printf("%s\n",entry->d_name);
}
return 0;
}
This will print the name of the first file in that directory. My problem is how to read that particular file's content and save it in a .txt document. Can ifstream do that? (Sorry for my bad English.)
this should do it
#include <iostream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace boost::filesystem;
using namespace std;
void show_files( const path & directory, bool recurse_into_subdirs = true )
{
if( exists( directory ) )
{
directory_iterator end ;
for( directory_iterator iter(directory) ; iter != end ; ++iter )
if ( is_directory( *iter ) )
{
cout << iter->native_directory_string() << " (directory)\n" ;
if( recurse_into_subdirs ) show_files(*iter) ;
}
else
cout << iter->native_file_string() << " (file)\n" ;
copyfiles(iter->native_file_string());
}
}
void copyfiles(string s)
{
ifstream inFile;
inFile.open(s);
if (!inFile.is_open())
{
cout << "Unable to open file";
exit(1); // terminate with error
}
//Display contents
string line = "";
//Getline to loop through all lines in file
while(getline(inFile,line))
{
cout<<line<<endl; // line buffers for every line
//here add your code to store this content in any file you want.
}
inFile.close();
}
int main()
{
show_files( "/usr/share/doc/bind9" ) ;
return 0;
}
If you're on Windows you can use the FindFirstFile in the Windows API. Here is a short example:
HANDLE myHandle;
WIN32_FIND_DATA findData;
myHandle = FindFirstFile("C:\\Users\\Toshiba\\Desktop\\links\\*", &findData);
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
cout << "Directoryname is " << findData.cFileName << endl;
}
else{
cout << "Filename is " << findData.cFileName << endl;
}
} while (FindNextFile(myHandle, &findData));
Otherwise I'd go with ayushs answer, Boost works for unix systems as well