Printing file directory into a data structure - c++

This code is suppose to read and print every single file in the directory, which is does. Now I want to be able to put those files in a data structure. I chose a list and the output cuts off before it gets to the actual file. How can I fix this?
"C:/Users/deonh/Downloads/intranets/intranet1\\page99.html" - What I want in the list
C:/Users/deonh/Downloads/intranets/intranet1 - What I get.
#include <iostream>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<fstream>
#include<string>
#include <filesystem>
namespace fs = std::filesystem;
using namespace std;
string path = "C:/Users/deonh/Downloads/intranets/intranet1"; //This gets every single file in the directory
string path5 = "C:/Users/deonh/Downloads/intranets/intranet5";
string path7 = "C:/Users/deonh/Downloads/intranets/intranet7";
int main()
{
list<string>pages;
map<string, int> page;
//Here I am printing the files to make sure the above code works.
for (const auto& entry : fs::directory_iterator(path)) {
std::cout << entry.path() << std::endl;
pages.push_back(path);
}
for (list<string> ::iterator it = pages.begin(); it != pages.end(); it++) {
cout << *it << endl;
}
return 0;
}

You are just adding the wrong value to the list
pages.push_back(path);
should be
pages.push_back(entry.path().generic_string());

Related

How to retain filesystem path while converting to string?

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
using namespace std;
int main()
{
fs::path p = fs::current_path();
cout << p << endl;
string p_string = p.string();
cout << p_string << endl;
return 0;
}
When printing out 'p' the path is shown as this.
"C:\\Users\\tp\\source\\repos\\test"
But after the conversion to a string it comes out like this.
C:\Users\tp\source\repos\test
Is there a way I could retain the original form of the path?
From cppreference's page on operator<<(std::filesystem::path):
Performs stream input or output on the path p. std::quoted is used so that spaces do not cause truncation when later read by stream input operator.
So we'll get the same string by manually calling std::quoted:
#include <iostream>
#include <iomanip>
#include <filesystem>
namespace fs = std::filesystem;
using namespace std;
int main()
{
fs::path p = fs::current_path();
// Should be same
cout << p << endl;
cout << std::quoted(p.string());
return 0;
}

How to read and output how many Bytes a folder has in it using C++ 17 filesystem on windows

I have a C++ program that takes a directory, like "D:\P4Test", and attempts to tell me how many bytes are in each subfolder and file within that directory. The code I currently have looks like this:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdint>
#include <sstream>
#include <filesystem>
using namespace std;
namespace fs = std::filesystem;
using namespace std::filesystem;
int main()
{
string path = "D:\\P4Test";
for (const auto& entry : directory_iterator(path)) {
cout << entry.path() << std::endl;
uintmax_t fsize = file_size(entry.path());
cout << " ||| " << fsize << endl;
}
}
Yes, it has a lot of unnecessary includes and such, but that's for future things.
When I run this code, I don't get what I want. Here's a picture of what's in that directory, and the output.
As you can see, the output looks good, but it does not give me the bytes for what's in the folders called "Two" & "Three".
Both folders have a text file in them that's 5 bytes, but they report back 0.
Can anyone help me figure out why, and show me how to make the folders show their bytes, or direct me to where I can figure this out?
It looks like you are trying to do a recursive file size check, but you do not actually recurse into the directories. 1 way to do this is to stasrt with a function gets all of the file sizes:
void folder_size(std::filesystem::path path) {
for (const auto& entry : directory_iterator(path)) {
cout << entry.path() << std::endl;
uintmax_t fsize = file_size(entry.path());
cout << " ||| " << fsize << endl;
}
}
Now we simply a special case to deal with if the file type is a directory, we can do this with std::filesystem::directory_entry::is_directory:
if (entry.is_directory()) {
// Handle the directory
}
So how do we handle the directory, well we have a function that we made that takes a directory path and goes through it. Lets call that:
if (std::filesystem::is_directory(entry.path())) {
folder_size(entry.path())
}
Putting it all together:
void folder_size(std::filesystem::path path) {
for (const auto& entry : directory_iterator(path)) {
cout << entry.path() << std::endl;
uintmax_t fsize = file_size(entry.path());
cout << " ||| " << fsize << endl;
if (std::filesystem::is_directory(entry.path())) {
folder_size(entry.path())
}
}
}
NOTE: All of the above is example code. No compilation check has been conducted.

a "?" before the string

I want to use strings to input the path of files:
char** argv;
char* mytarget[2]={ (char*)"‪D:\\testlas\\BigOne.pcd",(char*)"‪‪D:\\testlas\\SmallOne.pcd" };
argv = mytarget;
for(int i=0;i<2;i++)
{
std::cout << "m.name: " << argv[i] <<std::endl;
}
However, cout outputs:
m.name: ?‪D:\\testlas\\BigOne.pcd
m.name: ?‪D:\\testlas\\SmallOne.pcd
Why is there a ? before the strings?
I use VS2017 C++11.
I created a new program and used the code:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main()
{
std::string test = "‪abc789";
cout << test << endl;
return 0;
}
It also outputs "?abc789". Why?
std::string test = "‪abc789";
There is a hidden LEFT-TO-RIGHT EMBEDDING character between the opening quote " and the first letter a (Unicode character U+202A, or UTF-8 E2 80 AA). Remove it, for example by deleting and retyping the line, then the ? will go away.

stop recursion for recursive_directory_operator c++

So let's say i have this code that looks for documents of mine and prints the path to them.
#include <iostream>
#include <experimental/filesystem>
#include <string>
#include <stdio.h>
#include <Shlwapi.h>
using namespace std;
string extensions[3] = { ".doc", ".docx", ".txt" }; // things to look for
string ignoredirs[2] = { "Windows", "Program Files", } // and other ones that i was too
// lazy to write in there
using namespace std::experimental::filesystem;
path yee;
void main()
{
for (recursive_directory_iterator i("c:\\"), end; i != end; ++i)
if (!is_directory(i->path()) && i->path().has_extension()) // checks if the file
// even has an extension
{
for (int x = 0; x <= 3; ++x)
if (i->path().extension().string() == extensions[x])// checks if the
// extension is equal
// to current
// extension in loop
cout << "found document at :" ;
cout << i->path().string() << endl; // print out the path
}
}
And I would like to not iterate to directories in ignoredir[] because it takes ages to find my docs on the filesystem.
I saw this code from cppreference.com.
Could someone explain me the the code and/or how to use it in my use case?
Pr could you submit a better solution than that?
Ps. I don't want to use boost in this program, just to see how it works in experimental::filesystem
Proposed solution:
#include <iostream>
#include <experimental/filesystem>
#include <string>
#include <stdio.h>
#include <Shlwapi.h>
#include <set>
using namespace std;
set<string> extensions = { ".doc", ".docx", ".txt" }; //things to look for
set<string> ignoredirs = { "Windows", "Program Files" }; //and other ones that i was too lazy to write in there
using namespace std::experimental::filesystem;
int main()
{
for (recursive_directory_iterator i("c:\\"), end; i != end; ++i)
{
if (!is_directory(i->path()) && i->path().has_extension()) // checks ifthe file even has an extension
{
if (extensions.find(i->path().extension().string()) != extensions.end())
cout << "found document at :";
cout << i->path().string() << endl; //print out the path
}
if (ignoredirs.find(i->path().filename().string()) != ignoredirs.end())
i.disable_recursion_pending();
}
}
Explanation:
i->path().filename() actually return directory name, when the same directory name is in set<> then i.disable_recursion_pending(); is called. When this one is called recursive_directory_iterator i omit directory with i->path().filename() name.
set<string> was used to get rid internal for loop that requires size of table, which is error prone. Also performance gain and code simplification
Notice:
On windows directory names should be compared case insensitive. Also Windows 64bit have "Program Files" and "Program Files (x86)" and both need to be listed in ignore list (or string comparison need to be improved)

How to group data while iterating through a directory in c++

I have a directory with 15 folders and each folder has 100 of text files. In each text files contains a column of numbers.
I need those numbers to do some calculations, but I cannot figure out how to obtain it. I was thinking about a 2D vector, but I need different type of data structure (string for the name of the folder and interger for the numbers).
What is my best solution?d
What I got so far is a code that will search all the files by given a path.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <tuple>
#include <boost/filesystem.hpp>
#include<dirent.h>
using namespace std;
namespace fs = boost::filesyst
// prototype to search all the files by given it a path
vector<double> getFilesFromDirectory(const fs::path& startDirectory);
int main()
{ // the directory
string dir = "/home/...";
// testing to call my methode
vector<double> myDataStructure = getFilesFromDirectory(dir);
// print out the value of myDataStructure
for (auto it = myDataStructure.begin(); it != myDataStructure.end(); it++)
{
cout << *it << " " << endl;
}
return 0;
}
// methode to search all the files by given it a path
vector<double> getFilesFromDirectory(const fs::path& startDirectory)
{
vector<double> di;
// First check if the start path exists
if (!fs::exists(startDirectory) || !fs::is_directory(startDirectory))
{
cout << "Given path not a directory or does not exist" << endl;
exit(1);
}
// Create iterators for iterating all entries in the directory
fs::recursive_directory_iterator it(startDirectory); // Directory iterator at the start of the directory
fs::recursive_directory_iterator end; // Directory iterator by default at the end
// Iterate all entries in the directory and sub directories
while (it != end)
{
// Print leading spaces
for (int i = 0; i < it.level(); i++)
cout << "";
// Check if the directory entry is an directory
// When directory, print directory name.
// Else print just the file name.
if (fs::is_directory(it->status()))
{
// print out the path file
cout << it->path() << endl;
}
else
{
cout << it->path().filename() << endl;
// test
di = getValueFromFile(it->path().c_str());
// test, here I want to group the numbers of the file
// and each name of the folder
for(int i = 0; i < 15; i++)
{
di.push_back(mi(fs::basename(it->path()), it->path().c_str());
}
}
// When a symbolic link, don't iterate it. Can cause infinite loop.
if (fs::is_symlink(it->status()))
it.no_push();
// Next directory entry
it++;
}
return di;
}
If I understand the problem correctly, I'd write a class (or struct) to hold the contents of each file:
A string containing the path:
A vector containing every value represented in the column for that file
In your main program, a vector containing each object you create.
Definition:
#ifndef __COLVALS_HPP__
#define __COLVALS_HPP__
#include <vector>
#include <string>
class ColVals {
private:
std::vector<double> _colValues;
std::string _pathName;
public:
ColVals(const std::string& pathName);
~ColVals() {}
void appendValue(const double colValue);
std::vector<double> getValues();
std::string getPath();
};
#endif // __COLVALS_HPP__
Implementation:
#include "colvals.hpp"
using namespace std;
ColVals::ColVals(const string& pathName) {
_pathName = pathName;
}
void ColVals::appendValue(const double colValue) {
_colValues.push_back(colValue);
}
vector<double> ColVals::getValues() {
return _colValues;
}
string ColVals::getPath() {
return _pathName;
}