So I can print all the files in a folder but i'd like to print the files that I want. What I mean by that is that I will input for example Mineract, if I have in the folder, for example minecraft_server,mineract launcher. It would print all the names with Minecraft in they're names so it would print Minecraft server and Mineacraft Launcher
I've tried putting it in a for loop. But i can not do the I position of path it's not possible.
for (const auto& entry : fs::directory_iterator(path))
{
cout << entry.path() << endl;
}
That would just print all the files.
UPDATED CODE (still doesn't work).
search - What ever the user inputs
for (const auto& entry : fs::directory_iterator(path)) {
if (entry.path().string().find(search) != string::npos) {
cout << entry.path().string() << endl;
}
}
If I understand your question correctly which I seriously doubt, you want to loop through a folder and its subfolders and only do something for files that contain a certain string.
The following (off top of my head) would work
#include <experimental/filestream>
namespace fs = std::experimental::filestream
for (auto& file : fs::recursive_directory_iterator(yourPath))
{
if(file.path().u8string().find(yourString) != std::string::npos)
do your stuff
}
This example comes straight from code I used for 8 weeks straight and it never failed on me:
for (auto file : fs::recursive_directory_iterator("./"))
{
//std::cout << file.path().u8string() << std::endl;
if (includedFiles.find(file.path().u8string()) != includedFiles.end()
|| skipFile(config, files, &file)
|| file.path().u8string().find((*config)["testFile"].get<std::string>()) != std::string::npos
|| file.path().u8string().find((*config)["outputFile"].get<std::string>()) != std::string::npos
|| matchRegex(&fileOrder, &file.path().u8string())) // Last one does ordering
{
//if (file.path().u8string().find("ValidateModel") != std::string::npos)
//{
// std::cout << "skipped model string " << file.path().u8string() << std::endl;
//}
continue;
}
includedFiles[file.path().u8string()] = true;
std::cout << file.path().u8string() << std::endl;
functor(file);
}
Full code minus the library is available at github: https://github.com/erikknaake/IseProjectSQLFileCombiner/blob/master/SQLFileCombiner.cpp
When you know the name of the folder:
std::string path = std::cin;
for (auto& file : fs::recursive_directory_iterator(path))
{
do your stuff
}
Maybe you need to prepend a /
Related
I want to implement recursive directories and files listing on my own. I do not want to use
std::filesystem::recursive_directory_iterator
I tried this code:
void TraverseDirectory(const std::string& rootDirectory)
{
//Go thru the root directory
for(const auto& entry : std::filesystem::directory_iterator(rootDirectory)) {
std::string filenameStr = entry.path().filename().string();
//if the first found entry is directory go thru it
if(entry.is_directory()) {
std::cout << "Dir: " << filenameStr << '\n';
TraverseDirectory(filenameStr);
}
//print file name
else if(entry.is_regular_file()) {
std::cout << "file: " << filenameStr << '\n';
}
}
}
int main()
{
TraverseDirectory("testdir");
}
but it gives me this error when the main loop enters TraverseDirectory(filenameStr);:
How can I iterate over directories and its files without the error shown above?
std::filesystem::path::filename
Returns the generic-format filename
component of the path.
Equivalent to relative_path().empty() ? path() : *--end().
This means, that for actual path /foo/bar/42.txt you get 42.txt return. Now, here in
if(entry.is_directory()) {
std::cout << "Dir: " << filenameStr << '\n';
TraverseDirectory(filenameStr);
}
Your recursive call receives only filename part of path, hence tries to walk into bar, instead of foo/bar for example.
So you better off changing that to
TraverseDirectory(entry.path());
I'm having a bit of a problem with the code below.
#include <iostream>
#include <fstream>
#include <string>
#include <map>
std::map<std::string, int> m; //Dictionary map
int main() {
std::ifstream dictionaryFile("dictionary.txt");
std::string str;
int probability = -1;
//Read dictionary.txt and assign to map
while(std::getline(dictionaryFile, str)) {
if(str.find("#!comment:") == std::string::npos) { //Not a comment
m.insert(std::pair<std::string, int>(str, probability));
}
else {
probability++;
}
}
dictionaryFile.close();
//Iterate and print through map -- THIS WORKS
std::map<std::string, int>::iterator pos;
for(pos = m.begin(); pos != m.end(); ++pos) {
std::cout << "Key: " << pos->first << std::endl;
std::cout << "Value: " << pos->second << "\n" << std::endl;
}
//Is "very" in the map? -- THIS DOES NOT WORK
std::cout << m.find("very")->second << std::endl;
if(m.find("very") != m.end()) {
std::cout << "found it" << std::endl;
} else {
std::cout << "did not find it" << std::endl;
}
}
I read in the "dictionary.txt" file, and insert each word into a map. Either 1 or 2 is the value associated with that key, depending on the probability of the word.
I'm able to iterate through the map and print it's elements from within a for-loop, as shown. But I'm unable to access each element individually with m.find(), m.count(), or the [] operator. Each of those show as if the map is empty.
Do I have a piece of syntax wrong? Have I discovered a bug in std::map? Any help would be appreciated!
Here is dictionary.txt if you would like it.
Your file contains Windows CRLF line endings \r\n. These are automatically translated into \n with the default istream processing on Windows. However, you are on a Linux system that will be treating your \r character as nothing particularly special.
There are various ways around this. The simplest would be to not use such files as inputs on Linux. You can find answers elsewhere on this site for how to convert line-endings in the shell.
If you absolutely want your program to handle them, then you need to introduce some extra code. It can be as simple as checking the last character:
if (!str.empty() && str.back() == '\r')
str.pop_back();
For pre-C++11 standard library that doesn't have std::string::pop_back, you can just call str.erase(str.size()-1) instead.
I have written a program to check for balanced curly brackets in a .cpp file. The program works fine and finds the syntax error, displays the number of the line with the problem and then exits.
But I have to display a different error message if the error is at the last line of the input cpp file.
I have tried to implement it like following way but I think it is wrong. It doesn't work anyway :)
else
{
if(current == inputFile.eof()) //THIS IS WHAT I TRIED
{
cout << "Syntax error at the end of the program.";
}
else
{
cout << "Syntax error in line: " << current << "\n";
errorFound == true;
}
}
I did not give the complete code because I think a simple if condition with the correct variable will solve this. If you need it, I can post the code later.
EDIT: Larger piece of the code is given as requested. counter is an int variable that is updated every line by counter++.
for(int i = 0; i < line.length(); i++)
{
if (line[i] == '{')
{
stack.push(current);
}
else if(line[i] == '}')
{
if (!stack.isEmpty())
{
stack.pop(opening);
cout << "Code block: " << opening << " - " << current << "\n";
}
else
{
if(current == inputFile.eof())
{
cout << "Syntax error at the end of the program.";
}
else
{
cout << "Syntax error in line: " << current << "\n";
errorFound == true;
}
}
}
This is the best solution I could think of. There is probably a better one.
std::ifstream input_file{ "file.txt };
std::vector<std::string> contents;
// fill vector with file contents
std::string cline;
while (std::getline(input_file, cline))
contents.push_back(cline);
// now loop
for (const auto& line : contents) {
//...
if (&line == &contents.back()) {
// do something at the end of file
}
}
You can use an iterator version if you don't like the pointer comparison :)
I am writing a todo list manager program in C++ and would like to do the following:
Check if a directory exists in the program's working directory, if not create it
If it does exist, get a list of .txt files from it.
Be able to create/delete .txt files from this directory
I have tried using boost/filesystem.hpp but can't seem to figure it out (or how to get it to link using g++). Below is an example of what I have tried (assume proper #includes's, int main, etc):
std::vector<std::string> findLists(void){
std::vector<std::string> lists;
std::string temp;
char dir[ MAX_PATH ];
std::string(dir, GetModuleFileName(NULL, dir, MAX_PATH));
dir = dir.substr(0,dir.find_last_of( "\\/" ));
path p(dir);
for(auto i = directory_iterator(p); i != directory_iterator(); i++){
if(!is_directory(i->path())){
temp = i->path().filename().string();
if(temp.compare(0,temp.find(".")+1,".txt")){
temp = temp.substr(0,temp.find("."));
}
lists.push_back(temp);
}
else{
continue;
}
}
return lists;
}
From Boost documentation
int main(int argc, char* argv[])
{
path p (argv[1]); // p reads clearer than argv[1] in the following code
if (exists(p)) // does p actually exist?
{
if (is_regular_file(p)) // is p a regular file?
cout << p << " size is " << file_size(p) << '\n';
else if (is_directory(p)) // is p a directory?
cout << p << "is a directory\n";
else
cout << p << "exists, but is neither a regular file nor a directory\n";
}
else
cout << p << "does not exist\n";
return 0;
}
You have all the facilities you need in there. This is only a starting point, but you should be able to get through it pretty quickly.
I'm having some trouble with the following function. It is supposed to be given a path and a set of allowed file extensions, then find all files in that path with any of those extensions. Instead it finds nothing and returns an empty set.
std::set<boostfs::path> scan_directory(const boostfs::path& p,
const bool recurse,
const std::set<std::string>& allowed) {
std::string ext ;
std::set<boostfs::path> incs, incs2 ;
boostfs::path::iterator itr ;
// Extract directory and filename
boostfs::path file = p.filename() ;
boostfs::path dir = p.parent_path() ;
std::cout << "path: " << p.string() << std::endl ;
for (itr = dir.begin(); itr != dir.end(); ++itr) {
if (boostfs::is_directory(*itr)) {
if (recurse) {
std::cout << "dir: " << itr->string() << std::endl ;
incs2 = scan_directory(*itr, true, allowed) ;
incs.insert(incs2.begin(), incs2.end()) ;
}
} else {
// Don't include the original source
if (*itr != p) {
// Include only allowed file types
ext = itr->extension().string() ;
std::cout << "file: " << itr->string() << std::endl ;
std::cout << "ext: " << ext << std::endl ;
if (allowed.find(ext) != allowed.end()) {
incs.insert(*itr) ;
}
}
}
}
return incs ;
}
The prints to cout are just for debugging. I'm testing it with the following directory structure:
./test/cpp/
foo.cpp
foo.h
test.cpp
./test/cpp/bar/
baz.cpp
baz.h
I invoke the function with the path "test/cpp/test.cpp", recurse true and a set containing one string ".cpp". I get the following output from the prints,
path: test/cpp/test.cpp
dir: test
path: test
file: cpp
ext:
Then the function ends and the rest of the program continues, only it's given an empty set of files so not much to work on. Given the test directory it should return a set containing "test/cpp/foo.cpp" and "test/cpp/bar/baz.cpp".
I'm fairly sure it worked not long ago, but I'm not sure when it broke or what I did that made it do so. I'm sure it's some small, annoying technicality.
I found my problem. I was using path::iterator instead of directory_iterator (or recursive_directory_iterator) so I was looping through the components of the path instead of the contents of the directory. I could have sworn it worked earlier, but that might just have been luck maybe.
Here's my working code
std::set<boostfs::path> scan_directory(const boostfs::path& p,
const bool recurse,
const std::set<std::string>& allowed) {
std::string ext ;
std::set<boostfs::path> incs ;
// Extract directory and filename
boostfs::path file = p.filename() ;
boostfs::path dir = p.parent_path() ;
boostfs::recursive_directory_iterator itr(dir), itr_end ;
while(itr != itr_end) {
if (boostfs::is_directory(*itr)) {
itr.no_push(!recurse) ;
} else {
// Don't include the original source
if (*itr != p) {
// Include only allowed file types
ext = itr->path().extension().string() ;
if (allowed.find(ext) != allowed.end()) {
incs.insert(*itr) ;
}
}
}
itr++ ;
}
return incs ;
}
I'll let it be known that the examples of iterating through directories in Boost's documentation are AWFUL