Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Recursing Search

luckyboyluckyboy Member Posts: 105
hey guys
this is my attempt to count all files in a gevin path
this code counts files and folders in drive "C:"
although, i repeated this algorithm many times, it still give me back unacceptable results
For example, it returns that it found 19 files in 21 folders
My CBuilder folder only contains 1000+ files

[code]
void __fastcall TForm1::FormCreate(TObject *Sender)
{
int files=0, dirs=0;
AnsiString path = "C:";
Search(path, files, dirs);
AnsiString result;
result.sprintf("%s %d %s %d %s", "Found", files, "files in", dirs, "folders");
MessageBox(0, result.c_str(), 0, 0);
}
//---------------------------------------------------------------------------
void __fastcall
TForm1::Search(AnsiString path, int &files, int &dirs)
{
TSearchRec data;
FindFirst(path+"\*.*", faAnyFile, data);
do
{
++files; // count every thing as file
if(data.Attr & faDirectory)
{
if(data.Name != "." && data.Name != "..")
{
--files; // if folders then decrement files
++dirs; // and increment dirs
path.sprintf("%s%s%s", path, "\", data.Name);
Search(path, files, dirs);
}
}
}while(!FindNext(data));
FindClose(data);
}
[/code]

M. Nasim

Comments

  • zibadianzibadian Member Posts: 6,349
    : hey guys
    : this is my attempt to count all files in a gevin path
    : this code counts files and folders in drive "C:"
    : although, i repeated this algorithm many times, it still give me
    : back unacceptable results
    : For example, it returns that it found 19 files in 21 folders
    : My CBuilder folder only contains 1000+ files
    :
    : [code]:
    : void __fastcall TForm1::FormCreate(TObject *Sender)
    : {
    : int files=0, dirs=0;
    : AnsiString path = "C:";
    : Search(path, files, dirs);
    : AnsiString result;
    : result.sprintf("%s %d %s %d %s", "Found", files, "files in", dirs, "folders");
    : MessageBox(0, result.c_str(), 0, 0);
    : }
    : //---------------------------------------------------------------------------
    : void __fastcall
    : TForm1::Search(AnsiString path, int &files, int &dirs)
    : {
    : TSearchRec data;
    : FindFirst(path+"\*.*", faAnyFile, data);
    : do
    : {
    : ++files; // count every thing as file
    : if(data.Attr & faDirectory)
    : {
    : if(data.Name != "." && data.Name != "..")
    : {
    : --files; // if folders then decrement files
    : ++dirs; // and increment dirs
    : path.sprintf("%s%s%s", path, "\", data.Name);
    : Search(path, files, dirs);
    : }
    : }
    : }while(!FindNext(data));
    : FindClose(data);
    : }
    : [/code]:
    :
    : M. Nasim

    It's better to count the files in an else part of the if(data.Attr & faDirectory) statement, instead of counting everything as a file. This will eliminate the . and .. directories as files.
    Are the files and dirs parameters variable (i.e. do they return their changed values back to the caller)?
  • luckyboyluckyboy Member Posts: 105
    : It's better to count the files in an else part of the if(data.Attr &
    : faDirectory) statement, instead of counting everything as a file.
    : This will eliminate the . and .. directories as files.

    Thanks for that comment
    I also correted the condition of do-while, since it was executing do statement without checking if FindFirst found something or not
    Although I'm sure FindFirst will find "." and ".." there.

    : Are the files and dirs parameters variable (i.e. do they return
    : their changed values back to the caller)?

    Ok, i can't make function return more than one value, so i passed parameters by REFERENCE not by VALUE
    look at the function header, there is ambrsand (&) before files and dirs
  • luckyboyluckyboy Member Posts: 105
    Where are you Mr. bilderbikkel
    I need your help here

    I changed the code to the following form to retrive which files found and watch if they have a special properties, but i found a very strange result.
    we have two Message boxes
    the first displays number of files and folders (witch were 51 files in 103 folders).
    the second displays the name of these files and folders (whitch was YServer.txt) only.
    where are the others ???

    [code]
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    int files=0, dirs=0;
    AnsiString path = "C:";
    Search(path, files, dirs);
    AnsiString result;
    result.sprintf("%s %d %s %d %s", "Found", files, "files in", dirs, "folders");
    MessageBox(0, result.c_str(), 0, 0);
    ShowMessage(Found);
    }
    //---------------------------------------------------------------------------
    void __fastcall
    TForm1::Search(AnsiString path, int &files, int &dirs)
    {
    TSearchRec data;
    FindFirst(path+"\*.*", faAnyFile, data);
    do
    {
    if(data.Attr & faDirectory)
    {
    if(data.Name != "." && data.Name != "..")
    {
    ++dirs; // if folder then increment dirs
    // Found is a member variable
    Found.sprintf("%s
    dir: %s", Found, data.Name);
    path.sprintf("%s%s%s", path, "\", data.Name);
    Search(path, files, dirs);
    }
    }
    else
    {
    ++files; // if file then increment files
    // Found is a member variable
    Found.sprintf("%s
    file: %s", Found, data.Name);
    }
    }while(!FindNext(data));
    FindClose(data);
    }
    [/code]
  • bilderbikkelbilderbikkel Member Posts: 754
    Try adding some additional debug output, using OutputDebugString.

    [code].
    void Search(AnsiString path, int &files, int &dirs)
    {
    OutputDebugString(AnsiString("Now searching following path: '"+path+"'.").c_str());

    TSearchRec data;

    FindFirst(path+"\*.*", faAnyFile, data);
    do
    {
    if(data.Attr & faDirectory)
    {
    if(data.Name != "." && data.Name != "..")
    {
    ++dirs; // if folder then increment dirs
    // Found is a member variable
    AnsiString found;
    found.sprintf("%s
    dir: %s", found, data.Name);
    path.sprintf("%s%s%s", path, "\", data.Name);
    OutputDebugString(found.c_str());
    Search(path, files, dirs);
    }
    }
    else
    {
    ++files; // if file then increment files
    // Found is a member variable
    AnsiString found;
    found.sprintf("%s
    file: %s", found, data.Name);
    OutputDebugString(found.c_str());
    }
    }
    while (!FindNext(data));
    FindClose(data);
    }
    [/code]

    And you'll find out what goes wrong.
  • luckyboyluckyboy Member Posts: 105
    thanks for all contributors
    the problem happened since the variable 'path' is being appended by 'NULL' every time recursion happen.
    I don't know why, but i tried to assign the value of data.Name many times to any [b]AnsiString variable[/b] and i got this error.

    the main point is to eliminate the use of such assignment, so i turned to [b]data.FindData.cFileName[/b] which is the char* version of [b]data.Name[/b].

    also, don't try to assign the value of data.FindData.cFileName to another char* variable through [b]initialization statement[/b] such as the following statement
    [code]
    subfolders.push_back(data.FindData.cFileName);
    [/code]
    given that subfolders is of type std::vector
    instead try to use the following alternative code
    [code]
    // 256 is the length of data.FindData.cFileName
    subfolders.push_back(new char[256]);
    strcpy(subfolders[directoryNumber], data.FindData.cFileName);
    [/code]

    here are the code to search entire path with any depth you need ;-)
    i tested it on my 200 GB Hard drive and it could search the entire partition without any error
    [code]
    TFileStream *file1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
    {
    file1 = new TFileStream("c:\output.txt", fmCreate);
    }
    //-----------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    int files = 0;
    int dirs = 0;
    AnsiString path = InputBox("search path", "enter path", "");
    if(path != "") {
    try {
    Search(path, files, dirs);
    }
    catch(Exception &exception) {
    exception.Message = "Insufficient memory";
    ShowMessage(exception.Message);
    }
    delete file1;
    path.sprintf("files = %d
    dirs = %d", files, dirs);
    ShowMessage(path);
    }
    }
    //---------------------------------------------------------------------------
    void __fastcall
    TForm1::Search(AnsiString path, int &files, int &dirs)
    {
    // part I, getting main forlder information
    TSearchRec data;
    int directoryNumber = 0; // number of directories in the the current folder only
    std::vector subfolders;
    try {
    FindFirst(path+"\*.*", faAnyFile, data);
    do
    {
    if(data.Attr & faDirectory)
    {
    if(data.Name != "." && data.Name != "..") {
    subfolders.push_back(new char[256]);
    strcpy(subfolders[directoryNumber], data.FindData.cFileName);
    ++dirs; // if folder then increment dirs
    ++directoryNumber;
    }
    }
    else
    {
    ++files; // if file then increment files
    }
    }while (!FindNext(data));
    FindClose(data);

    // part II, getting subfolders information
    for (int i=0; iWrite(tmp.c_str(), tmp.Length());
    Search(path + "\" + subfolders[i], files, dirs); // recursion.
    }
    }
    } // end of try block.

    // part III, free up memory
    catch(...) { // case 1: if excepion encountered.
    subfolders.erase(subfolders.begin(), subfolders.end());
    // rethrow exception to delete caller's subfolders array
    // and to stop more recursion calls with another subdirectory, by the caller
    throw;
    }
    // case 2: if there is no exception
    subfolders.erase(subfolders.begin(), subfolders.end());
    }
    [/code]
    thanks in advance, and special thanks to all contributors
    Mohammad Nasim
Sign In or Register to comment.