I changed this code a little. Now question one is answered - I won't be using integer number to indicate directories but lineInFile to indicate line of input file where I've got information about files stored in this directory. It also means that I don't create any temporary output file. But there are still questions number two and three. Second question is about creating tree structure. Third question is about showing list of directories and files from the actual directory (I don't know how to indicate actual directory and how to show it).
Code:
/*
Program of navigating the directory tree, displaying subdirectories and
files in current directory. The program uses output of the dir/s command.
It calculates total space occupied by files in subdirectories of selected
directory and calculates estimated disk space occupied by the files
considering the cluster size. The configuration data permitting the program
to determine the format of dir/s output (dos and windows, a few versions)
is stored in an external text file. The program should keep in RAM the
directory structure and the file names of files in current directory.
*/
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
class Directory
{
private:
//I don't use copy constructor and overloaded operator=. This is why I
//declare them here (in private) with no implementing - to prevent using them.
Directory::Directory(const Directory& dir)
{}
void Directory::operator=(const Directory& dir)
{}
public:
//Should I put name and lineInFile into private section?
string name; //name of the directory
vector<Directory*> children; //children directories
long int lineInFile; //What is the number of line in the file
//where list of files in this directory begins
//(don't mistake it with whereInFile)
Directory(string name_ = "No Name", long int lineInFile_ = -1) :
name(name_), lineInFile(lineInFile_) { }; //default constructor
//lineInFile == -1 means error
~Directory()
{
//delete children;
for (int i = 0; i<children.size(); i++)
{ delete children[i]; }
//example of how we can check size of vector:
//vector <int> vi_Tab(100);
//int i_Rozmiar = vi_Tab.size();
};
};
int nesting = 0;
void print(Directory *dir) { //my print function needs to take a pointer...
for (int i = 0; i < nesting; ++i) cout << ' ';
cout << dir->name << endl; //...so I've got this...
++nesting;
for_each(dir->children.begin(), dir->children.end(), print); //...and this.
--nesting;
}
int main()
{
ifstream fin("myfile.txt"); //to read list of directories
string line;
int counter=0;
long int whereInFile = 0; //what number of line in the file is the actual one
string nameMainDir; //it contains line " Directory: C:\root"
//where 'Directory' is word dependent on language version of dir/s
//and 'myRoot' is the name of main directory in our tree
size_t lengthOfNameMainDir; //I use it during next iterations
string myRoot; //it contains only name 'root'
vector<string> nameUpperChildren; //we've got root and its children UpperChildren
int whereInBlock=0; //inside the file there are blocks
//(every block begins with " Directory: " C:\root[...]")
//0 - it is new block, 1 - first line of new block, 2 - second,
//3 - third, 4 - it is inside this block, 5 - last line
string rhsDir; //name of the most RHS directory in the line
string actualName; //name of file or directory which I'm reading at this moment
int howManySlash; //it contains number of '/' symbols to know level of depth
string sizeInBytesString; //???????? I will take care of
long int sizeInBytes; //read size of the file //???????? these variables later.
//don't read first three lines
for (int i=0; i<3; i++) {getline(fin,line);}
//===========================================================================
while(getline(fin, line))
{
//-----------------------------------------------------------------------
//first iteration - it checks version of dir/s and reads name of main dir
//-----------------------------------------------------------------------
if (counter==0) //if it is first iteration, it reads nameMainDir
{
nameMainDir = line; //it reads first line
lengthOfNameMainDir=line.size(); //here I check size of the line
int i=lengthOfNameMainDir;
do { i--; } while (line[i]!=(char)92); //it counts from end of line
//to first use of symbol char(92)=='\'
myRoot=line.substr((i+1),(lengthOfNameMainDir-i)); //if writes name of root
//directory
counter++; //it disables entering this if any more
//Directory *root = new Directory(myRoot); //it creates root
Directory root(myRoot, whereInFile); //it creates object root
cout<<"myRoot :["<<myRoot<<"]"<<endl;
cout<<"nameMainDir :["<<nameMainDir<<"]"<<endl;
whereInBlock = 0; //because it's first line of the block
}
//----------------------------------------------------
//main part of this while - it reads tree of directory
//----------------------------------------------------
//if the line begins with nameDir, then it contains name of new directory
if (counter == 1) //I don't use else because it won't work for the very first line
{
//whereInBlock (the same comment is after declaration of whereInBlock):
//(every block begins with " Directory: " C:\root[...]")
//0 - it is new block, 1 - first line of new block, 2 - second,
//3 - third, 4 - it is inside this block, 5 - last
switch (whereInBlock)
{ //I haven't designed this switch yet :)
case 0: //it reads name of the RHS directory
if (line[2] == nameMainDir[2])
{ //if it is not one of last lines in the file (" Katalog" or " Razem")
//line - it is my line, nameMainDir - we need to erase it from rhs
//lengthOfNameMainDir - lenght
rhsDir = line.substr(lengthOfNameMainDir);
cout<<"rhsDir :["<<rhsDir<<"]"<<endl;
//now we need to calculate how many '/' there are in name
//so that we know level of depth in our directories tree
howManySlash = 0;
for (int i = 0; i<rhsDir.size(); i++)
{ if (rhsDir[i] == '\\') howManySlash++; }
whereInBlock++;
}
else
{ counter++; }
break;
case 1: whereInBlock++; break; //empty line
case 2: whereInBlock++; break; //line with .
case 3: whereInBlock++; break; //line with ..
case 4:
if (line[0] != ' ')
{ //case 4a - main body of the block
actualName = line.substr(36); //name of new file or directory
if (line[21] == '<') //it is directory
{
//SECOND QUESTION:
//Here I need to create new directory and I don't know how!
//At first time it is something like sub1, which is subdirectory of
//root. It should be something similar to:
//Directory *sub1 = new Directory("sub1", whereInFile);
//root.children.push_back(sub1); (or "root.children.push_back(sub1, whereInFile);" ?)
//but for next cases similar to:
//Directory *sub11 = new Directory("sub1.1");
//sub1->children.push_back(sub11);
//and I should be able to access it later.
//I should use "two stages: 1. create object,
//2. insert into tree (in right place)".
//Unfortunately still I don't know how to do it.
}
}
else
{ //case 4b - line before the last one
whereInBlock++;
}
break;
case 5: //again empty line
whereInBlock = 0;
break;
} //end of "switch"
} //end of "if (counter == 1)"
//----------------------------------------------------
//last and very short part of this while
//----------------------------------------------------
//every iteration it should increase whereInFile by one
whereInFile++;
} //end of "while(getline(fin, line))"
//===========================================================================
cout<<"::End of file::\n";
fin.close();
system("pause");
system("cls");
//I finished reading tree from the file. I've got tree structure in RAM
//and files are still in the input file. I don't read list of files into RAM.
//Now I can allow the user to navigate the tree.
//User can see the list of directories and write commands ".." for the
//previous directory or "[name]" to enter the directory given by [name].
//There may be "." for entering main directory.
//There should be key shortcut (e.g. ctrl+esc or ctrl+Q) to exit
//(by the way I don't know how to implement it). I need to implement
//here "while(key_is_not_pressed) { let_user_explore_the_structure; }".
//I will be using something like console to communicate with the user.
//THIRD QUESTION: I want to show directories and files in the actual directory
//(at the beginning it is root directory). I don't want to show the whole
//structure by "print(&root);". I'd like to show only actual directory
//but I don't have any idea how to indicate which directory is actual and
//how to show this directory. I should be able to show list of files in the
//actual directory (I don't store those files in RAM or other temporary txt
//file so I need to reopen fin, use lineInFile of the actual directory and
//read list of files from opened file.
system("pause");
return 0;
}
Regards!