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.
Related
I have a pair of header files. Within IsingModel.h, publically I declare:
ofstream logfile1;
ofstream logfile2;
Then to open the relevant files (logfile1 and logfile 2 have different names) I use:
do {
name2.str(""); //reset name stringstream
n++; //increase n value
name2 << "output_" << gridSize << "_" << seed << "_" << n << "_eqmCalc.txt"; //stream created
} while (if_exist(name2.str())); //test if file already exists
logfile2.open(name2.str());
Which works in creating the file. Then, throughout the code I use the ofstreams to act on the files, for example:
logfile1 << counter << " " << calcM() << " " << calcE() << endl;
This is fine for actions that are independent for each file, however when I call the destructor I want to write the same standard information to each file. To that end, I am experimenting with iteratively writing to the files and it does not seem to work:
void IsingSystem::test() {
for (int i = 1; i = 2; i++) {
if (ofstream("logfile" + to_string(i)).is_open); {
ofstream("logfile" + to_string(i)) << "success" << endl;
}
}
}
This instead creates files called logfile1 and logfile2. As an alternative, I tried to create an array of ofstreams:
void createFileHandles() {
const int count = 2;
std::ofstream logfile[count];
}
But, I could not work out how to pass this between functions properly.
What is the proper way of handling ofstreams so that I can have multiple files open, writing different instructions to them simultaneously but also have some actions that happen to both?
You can have a vector of ofstream
vector<ofstream> ofstreams(2);
//fill vec
for (int i = 0; i < 2; i++)
{
if (ofstreams[i].is_open);
{
ofstreams[i]<< "success" << endl;
}
}
You can then pass ofstreams to functions.
so I worked on my program and now I am on a point where I can not find a solution. I need to replace some more signs in the fext file, for now the program only replaces "TIT" with the code number "*245$a", if I want to replace other letters the same way, the program does not change. Does anybody know how I can implement some more replacements in the text file? Let me know if there is a better option to replace more than 5 signs with another ones.
Thank you
#include <fstream>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
char dateiname[64], kommando[64];
ifstream iStream;
cout << "Choose an activity" << endl <<
" s - search " << endl <<
" c - convert" << endl <<
" * - end program" << endl;
cin.getline(kommando,64,'\n');
switch(kommando[0])
{
case 'c':
cout << "Enter a text file!" << endl;
cin.getline(dateiname,64,'\n');
iStream.open("C://users//silita//desktop//schwarz.txt");
case 's':
break;
case '*':
return 0;
default:
cout << "I can not read " << kommando << endl;
}
if (!iStream)
{
cout << "The File" << dateiname << "does not exist." << endl;
}
string s;
char o[] = "TIT";
while (getline(iStream, s))
{
while(s.find(o, 0) < s.length())
s.replace(s.find(o, 0), s.length() - s.find(o, 3),"*245$a");
cout << s << endl;
}
iStream.close();
}
You can use map in C++ STL to store multiple convert rules:
#include<map>
#include<algorithm>
using namespace std;
map<string,string> convertRules;
typedef map<string,string>::iterator MIT;
void setConvertRules(int numOfRules){
string word,code;
for(int i = 0 ; i < numOfRules; ++i){
cin>>word>>code;
//Use code as search key in order to decrypt
//If you want to encrypt, use convertrules[word] = code;
convertRules[code] = word;
}
}
To convert a file, just do as follows (some functions and classes need to be declared and implemented first, but here we mainly focus on top-level design):
/* Detailed class implementations are omitted for simplicity */
//a class to store contents of a file
class File;
//a processor to read, insert and overwrite certain file
class FileProcessor;
void FileProcessor::convert(const string &code, const string &word){
cursor == file.begin();
while(cursor != fp.end()){
_fp.convertNextLine(code,word);
}
}
File file;
FileProcessor filePcr;
int main()
const string sourceDir = "C://users//silita//desktop//schwarz.txt";
const string destDir = "C://users//silita//desktop//schwarz_decrypted.txt";
//Open a .txt file and read in its contents
if (!file.openAndReadIn(sourceDir)){
cerr << "The File" << sourceDir << "does not exist." << endl;
abort();
}
//Try to link processor to open file
if(!fp.linkTo(file)){
cerr << "Access to file" << sourceDir << "is denied." << endl;
abort();
}
//iterator is like a more safe version of C-style pointer
//the object type is a string-string pair
for(MIT it = convertRules.begin(); it != convertRules.end(); ++it){
fp.convert(it->first, it->second);
}
file.saveAs(destDir);
return 0;
}
Finally, if I would suggest you use C-style strstr function for efficiency when dealing with large files or batch processing. string::find adopts a naive sequential search startegy while strstr is implemented with the famous KMP algorithm for fast pattern match in strings, which is both efficient and thorough(can replace all matchs in one go instead of another for-loop).
Im having trouble accessing the following vector. Im new to vectors so this is probably a small syntactical thing i've done wrong. here is the code....
void spellCheck(vector<string> * fileRead)
{
string fileName = "/usr/dict/words";
vector<string> dict; // Stores file
// Open the words text file
cout << "Opening: "<< fileName << " for read" << endl;
ifstream fin;
fin.open(fileName.c_str());
if(!fin.good())
{
cerr << "Error: File could not be opened" << endl;
exit(1);
}
// Reads all words into a vector
while(!fin.eof())
{
string temp;
fin >> temp;
dict.push_back(temp);
}
cout << "Making comparisons…" << endl;
// Go through each word in vector
for(int i=0; i < fileRead->size(); i++)
{
bool found = false;
// Go through and match it with a dictionary word
for(int j= 0; j < dict.size(); j++)
{
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
{
found = true;
}
}
if(found == false)
{
cout << fileRead[i] << "Not found" << endl;
}
}
}
int WordCmp(char* Word1, char* Word2)
{
if(!strcmp(Word1,Word2))
return 0;
if(Word1[0] != Word2[0])
return 100;
float AveWordLen = ((strlen(Word1) + strlen(Word2)) / 2.0);
return int(NumUniqueChars(Word1,Word2)/ AveWordLen * 100);
}
The error is in the lines
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
and
cout << fileRead[i] << "Not found" << endl;
the problem seems to be, because its in the form of a pointer the current syntax im using to access it is made invalid.
Using [] on a pointer to a vector will not call std::vector::operator[]. To call std::vector::operator[] as you want, you must have a vector, not a vector pointer.
The syntax to access the n-th element of a vector with a pointer to the vector would be: (*fileRead)[n].c_str().
However, you should just pass a reference to the vector:
void spellCheck(vector<string>& fileRead)
Then it's just:
fileRead[n].c_str()
You can use the unary * to get a vector& from a vector*:
cout << (*fileRead)[i] << "Not found" << endl;
Two options to access:
(*fileRead)[i]
fileRead->operator[](i)
One option to improve the method
pass by reference
You can either pass fileRead by reference like this:
void spellCheck(vector<string> & fileRead)
Or add a dereferece when you use it like this:
if(WordCmp( (*fileRead)[i]->c_str(), dict[j].c_str()) != 0)
I'm looking for a function that will return a list of what is in a particular directory.
The closest that I have gotten is by using this:
system("dir");
But this only prints the contents of the working directory, and I can't CD to anywhere else.
I'm using windows, and I have no plans to make it cross-platform, so don't worry about that.
Look at the following example directly copied from this page. It uses boost::filesystem so works on all major systems.
int main(int argc, char* argv[])
{
path p (/* Specify a directory here */);
try
{
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 containing:\n";
copy(directory_iterator(p), directory_iterator(), // directory_iterator::value_type
ostream_iterator<directory_entry>(cout, "\n")); // is directory_entry, which is
// converted to a path by the
// path stream inserter
}
else
cout << p << " exists, but is neither a regular file nor a directory\n";
}
else
cout << p << " does not exist\n";
}
catch (const filesystem_error& ex)
{
cout << ex.what() << '\n';
}
return 0;
}
I am working on a project to make a database of the files I have on current directory. And one of the details I want about my files is the file permissions that are set with chmod in ubuntu. (just a note: I will be needing the group and owner info too - like chown- and if you could let me know if boost can retrieve the ownership info too that'd be great.)
I am using boost filesystem library and I have checked the documentation for numerous times but couldn't find how to get the permissions.
In this page it shows that there's enum perms that has the file permission strings which doesn't show up on my own filesystem.hpp. (And I have checked that i've got the 1.49 version, also built from the source just to be sure). Also on the same page here it shows that it can get the permissions like:
perms permissions() const noexcept;
//Returns: The value of
//permissions() specified by the postconditions of the most recent call
//to a constructor, operator=, or permissions(perms) function.
I haven't been able to find the permissions function nor the place where it stores the perms list.
This is the code I have so far (which is actually from boost tutorials, but I modified it to be recursive), if you could tell me how to get the file permissions/ownerships or suggest another library than boost I would appreciate it.
EDIT: I have added the s.permissions() as ethan_liou suggested however the output was not as expected. Here's the updated code and the output.
// filesystem tut4.cpp ---------------------------------------------------------------//
// Copyright Beman Dawes 2009
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
// Library home page: http://www.boost.org/libs/filesystem
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <stdio.h>
using namespace std;
using namespace boost::filesystem;
int read(path p);
int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "Usage: tut4 path\n";
return 1;
}
path p (argv[1]); // p reads clearer than argv[1] in the following code
read(p);
return 0;
}
int read(path p) {
try
{
if (exists(p)) // does p actually exist?
{
if (is_symlink(p)) {
cout << p << " is a link\n";
}
else if (is_regular_file(p)) {
// is p a regular file?
file_status s = status(p);
cout << p << " size is " << file_size(p) << " perms " << "" ;
printf("%o\n",s.permissions());
}
else if (is_directory(p)) // is p a directory?
{
cout << p << " is a directory containing:\n";
typedef vector<path> vec; // store paths,
vec v; // so we can sort them later
copy(directory_iterator(p), directory_iterator(), back_inserter(v));
sort(v.begin(), v.end()); // sort, since directory iteration
// is not ordered on some file systems
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
{
//cout << " " << *it << '\n';
read(*it);
}
}
else
cout << p << " exists, but is neither a regular file nor a directory\n";
}
else
cout << p << " does not exist\n";
}
catch (const filesystem_error& ex)
{
cout << ex.what() << '\n';
}
return 0;
}
Output:
$ ./a.out ~/Desktop/test
"/home/usr/Desktop/test" is a directory containing:
"/home/usr/Desktop/test/a.out" size is 69446 perms 27746424350
"/home/usr/Desktop/test/la" is a directory containing:
"/home/usr/Desktop/test/la/Untitled Document" size is 0 perms 27746424170
"/home/usr/Desktop/test/la/lala" is a directory containing:
"/home/usr/Desktop/test/la/lala/Link to lalalala" is a link
"/home/usr/Desktop/test/la/lala/Untitled Folder" is a directory containing:
"/home/usr/Desktop/test/la/lala/lalalala" size is 0 perms 0
"/home/usr/Desktop/test/test.cpp" size is 2234 perms 0
"/home/usr/Desktop/test/test.cpp~" size is 2234 perms 0
Note: Those numbers that are like 27746424350 change each time the program is executed.
perms permissions() const { return m_perms; }
defined in boost/filesystem/v3/operations.hpp
Add an easy sample code
#include <boost/filesystem.hpp>
#include <stdio.h>
namespace fs=boost::filesystem;
int main(int argc,char * argv[]){
fs::path p(argv[1]);
fs::file_status s = status(p);
printf("%o\n",s.permissions());
}
File permissions example for windows:
unsigned long attributes = ::GetFileAttributes( filePath.file_string().c_str());
if ( attributes != 0xFFFFFFFF && ( attributes & FILE_ATTRIBUTE_READONLY ))
{
attributes &= ~FILE_ATTRIBUTE_READONLY;
::SetFileAttributes( filePath.file_string().c_str(), attributes );
}