CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - BCB6, skanowanie katalogu z dysku + zapis do StringGrid

BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Problemy związane z tworzeniem i zarządzaniem programami bazo-danowymi.
Regulamin działu


Zadając pytania dotyczące baz danych należy podawać szczegółowe informacje o bazie danych nad którą się pracuje, czyli:

  • Rodzaj serwera bazodanowego: MySql, MSSQL, Oracle itp.
  • Wersja bazy danych
  • Technologia bazodanowa używana w programie: ADO, DbExpress, InterBase
  • Komponenty użyte do zestawienia połączenia: ADOConnection, SqlConnection
  • Sposób zestawienia komponentów bazodanowych np. DataSet - DataSource - DbGrid lub DataSet - DataSetProvider - ClientDataSet - DataSource - DbGrid
  • Jeżeli używane były biblioteki innych firm niż Borland, CodeGeer i Embarcadero proszę podać ich nazwy, numer wersji i adres źródła.

BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez samurai-jerry » czwartek, 10 marca 2011, 15:22

Witam,

Piszę moduł odpowiedzialny za sprawdzenie, czy w danym katalogu (i jego podkatalogach) są inne katalogi i pliki.
Moduł pisany jest w środowisku Borland C++ Builder 6.
Wyniki są wypisywane w tabeli StringGrid1.
Dalsze szczegóły o założeniach modułu opisuję niżej.

Program oparłem na funkcji napisanej przez Cyfrowego Barona o nazwie: FindDir.
Funkcja FindDir (ta oryginalna) posiada w pewnej wersji algorytm rekurencji, który umożliwia właśnie operację o którą mi chodzi, tzn. wypisanie wszystkich podkatalogów (i plików) a nie tylko tych podkatalogów z katalogu podanego w szukanej ścieżce (pole Edit1).
Odpowiednikiem funkcji FindDir w mojej aplikacji jest funkcja ScanDir, której jednak nie udaje mi się napisać w taki sposób, aby stosowała algorytm rekurencyjny z założeniami jakie ma spełniać mój moduł.

Zanim napiszę o założeniach modułu pozwólcie, że opiszę tabelę StringGrid1.

Tabela StringGrid1 w moim module posiada 5 kolumn. Idąc od lewej do prawej, są to:
- liczba porządkowa ("L.p."),
- nazwa skanowanego obecnie katalogu ("Skanowany katalog" - uwaga! to nie jest sr.Name),
- informacja czy wewnątrz skanowanego katalogu są podkatalogi ("Są w nim katalogi?"),
- informacja czy wewnątrz skanowanego katalogu są pliki ("Są w nim pliki?"),
- "Ścieżka do skanowanego katalogu"

Dane do tabeli są wczytywane ze struktury info - zdefiniowanej i zadeklarowanej na początku modułu Unit1.cpp
Do tej struktury trafiają dane pochodzące z cyklicznego przeglądania zawartości katalogu, którego nazwa wraz ze ścieżką dostępu została wpisana do pola edycyjnego Edit1.

Założenia modułu skanowania:
1. Moduł ma umożliwić wypisanie wszystkich podkatalogów i plików, z każdego jednego podkatalogu względem tego katalogu wpisanego w polu edycyjnym Edit1
2. Moduł ma wyświetlać w 3-ciej (licząc od 1) kolumnie czy w katalogu, który jest obecnie przeglądany (listingowany?-może to lepsze słowo) jest katalog, a w 4-tej kolumnie czy jest plik. Nazwa zarówno katalogu, czy to pliku nie ma być wyświetlana. Ma być jedynie informacja czy są jakieś katalogi lub/i pliki (algorytm dobrnął do końca gałęzi drzewa danego podkatalogu).

Mam problem z umiejscowieniem rekurencyjnego wywołania funkcji ScanDir (w ciele jej samej-wiadomo)...
Próbowałem już wielu sposobów i coś robię nie tak! Za nic nie mogę wpaść co robię nie tak... :( - Pomóżcie!!! Proszę!!!

Oto mój kod pliku nagłówkowego - Unit1.h:
KOD cpp:     UKRYJ  
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Grids.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TPanel *Panel1;
        TButton *Button1;
        TStringGrid *StringGrid1;
        TEdit *Edit1;
        TLabel *Label1;
        TLabel *Label2;
        TButton *Button2;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall FormCreate(TObject *Sender);
        void __fastcall Button2Click(TObject *Sender);
private:        // User declarations
public:         // User declarations
        __fastcall TForm1(TComponent* Owner);
        void __fastcall WypiszNaglowekTabeli(TStringGrid *StringGrid1);
        void __fastcall WypelnijTabele(TStringGrid *StringGrid1, String Dir);
        void __fastcall ScanDir(TStringGrid *StringGrid1, String Dir);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
 


Oto mój kod pliku źródłowego - Unit1.cpp:
KOD cpp:     UKRYJ  
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

struct info_str
       {
       String skan_dir;
       String is_dirs_inside;
       String is_files_inside;
       String path_2_skan_dir;
       };
info_str info;

TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::WypiszNaglowekTabeli(TStringGrid *StringGrid1)
{
StringGrid1->Cells[0][0]="L.p.";
StringGrid1->Cells[1][0]="Skanowany katalog";
StringGrid1->Cells[2][0]="Są w nim katalogi?";
StringGrid1->Cells[3][0]="Są w nim pliki?";
StringGrid1->Cells[4][0]="Ścieżka do skanowanego katalogu";
// StringGrid1->FixedRows=1;
}

void __fastcall TForm1::WypelnijTabele(TStringGrid *StringGrid1, String Dir)
{
StringGrid1->RowCount = StringGrid1->RowCount + 1;
StringGrid1->Cells[0][StringGrid1->RowCount-1] = StringGrid1->RowCount-1;
StringGrid1->Cells[1][StringGrid1->RowCount-1] = info.skan_dir;
StringGrid1->Cells[2][StringGrid1->RowCount-1] = info.is_dirs_inside;
StringGrid1->Cells[3][StringGrid1->RowCount-1] = info.is_files_inside;

if (Dir.Length()>0 && Dir.Length()<=6)
   {
   /* gdyby skanowany był cały dysk np. C:\ */
   info.path_2_skan_dir=ExtractFileDir(Dir);
   }
   else
       {
       info.path_2_skan_dir=ExtractFileDir(Dir)+"\\";
       }

info.is_files_inside="brak plików";
info.is_dirs_inside="brak katalogów";
}

void __fastcall TForm1::ScanDir(TStringGrid *StringGrid1, String Dir)
{
TSearchRec sr;
// StringGrid1->RowCount = 1; // niech nie zaczyna od nagłówka! tylko od następnego wiersza
Dir=Dir+"*.*";
if (FindFirst(Dir, faAnyFile, sr) == 0)
   {
   do
     {
     if (sr.Name!="." && sr.Name!="..")
        {
        // info.skan_dir=ExtractFileDir(Dir);
        info.skan_dir=ExtractFileName(info.skan_dir);
        if ((sr.Attr & faArchive) == sr.Attr)
           {
           info.is_files_inside="pliki są";
           }
        if ((sr.Attr & faDirectory) == sr.Attr)
           {
           info.is_dirs_inside="katalogi są";
           }
        }
     } // do while
   while (FindNext(sr) == 0);
   // ScanDir(StringGrid1, Dir);
   WypelnijTabele(StringGrid1, Dir);
   // StringGrid1->RowCount=StringGrid1->RowCount +1;
   StringGrid1->RowCount++;
   FindClose(sr);
   }
   else
       {
       // nie wiem jaki sensowny komunikat
       // tutaj umieścić... :/
       ShowMessage("FindFirst(Dir, faAnyFile, sr) != 0");
       }
WypiszNaglowekTabeli(StringGrid1);
// StringGrid1->FixedRows=1;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (int y=0; y<StringGrid1->RowCount; y++)
    {
    StringGrid1->Rows[y]->Clear();
    }
StringGrid1->RowCount=0;
ScanDir(StringGrid1, Edit1->Text);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Edit1->Text="C:\\";
WypiszNaglowekTabeli(StringGrid1);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Application->Terminate();
}
 


Naprawdę bardzo mocno proszę! - POMÓŻCIE!!!

Pozdrawiam! samurai-jerry

P.S. W załączniku wysyłam kod źrodłowy + plik.exe
P.S.2. Piszę post tutaj (Bazy danych), ponieważ w dalszych założeniach moduł ten ma realizować założenia bazy danych.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
"No pain no gain" - Scorpions
Avatar użytkownika
samurai-jerry
Bladawiec
Bladawiec
 
Posty: 24
Dołączył(a): sobota, 19 lutego 2011, 19:04
Podziękował : 15
Otrzymał podziękowań: 0
System operacyjny: W98,W2K,WXP
Kompilator: Borland C++ Builder v6.0 Personal
wxDevCpp v.6.9
ChromeIDE+Masm32
KDevelop
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez Cyfrowy Baron » czwartek, 10 marca 2011, 18:30

samurai-jerry napisał(a):Mam problem z umiejscowieniem rekurencyjnego wywołania funkcji ScanDir


Oczywiście wewnątrz funkcji wyszukującej.



twój kod nie ma większego sensu. Struktura się nie sprawdzi, gdyż zamierzasz jej używać do przechowywania znalezionych plików i folderów, ale w strukturze zadeklarowałeś tylko po jednej zmiennej, więc jak miałyby przechowywać cokolwiek. Tutaj trzeba by raczej użyć wektorów.

Zobaczę to w wolnej chwili, ale niczego nie obiecuję...

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
samurai-jerry
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez Cyfrowy Baron » czwartek, 10 marca 2011, 18:56

Nie wiem o co dokładnie Tobie chodzi, gdyż mimo iż Twój opis jest rozwlekły, to jest jednocześnie zbyt zawiły. Przypuszczam, że chodzi mniej więcej o coś takiego:

KOD cpp:     UKRYJ  
void __fastcall TForm1::WypelnijTabele(TStringGrid *StringGrid1, String Value,
        int col)
{
 StringGrid1->Cells[col][StringGrid1->RowCount - 1] = Value;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ScanDir(TStringGrid *StringGrid1, String Dir)
{
 TSearchRec sr;

 if(FindFirst(Dir + "*.*", faAnyFile, sr) == 0)
 {
   do
   {
    if( /*((sr.Attr & faDirectory) > 0) & */(sr.Name != ".") & (sr.Name != ".."))
    {
     if((sr.Attr & faDirectory) > 0)
     {
      ScanDir(StringGrid1, Dir + sr.Name + "\\");

      WypelnijTabele(StringGrid1, sr.Name, 1);
      WypelnijTabele(StringGrid1, "Katalogi są", 2);
      WypelnijTabele(StringGrid1, Dir + sr.Name, 4);
     }
     else
     {
      /* tutaj wrpowadzasz pliki, np:
      WypelnijTabele(StringGrid1, sr.Name, numer_kolumny_na_pliki); */

      WypelnijTabele(StringGrid1, "Pliki są", 3);
     }


     StringGrid1->RowCount += 1;
     WypelnijTabele(StringGrid1, (String)StringGrid1->RowCount, 0);
    }

    Application->ProcessMessages();
   }
   while (FindNext(sr) == 0);
   FindClose(sr);
 }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 /* y = 1 bo kolumna nagłówka nie wymaga czyszczenia */
 for (int y = 1; y < StringGrid1->RowCount; y++)
 {
  StringGrid1->Rows[y]->Clear();
 }

 StringGrid1->RowCount = 2; /* co najmniej 2 jeżeli ma pozostać kolumna nagłówka */
 ScanDir(StringGrid1, Edit1->Text);
}


Przytoczyłem tutaj tylko kod, który zmieniłem w Twoim programie. Struktura jest nieprzydatna, więc zbędna.
Kod ma jedną wadę - wylicza najpierw podkatalogi, a potem katalogi. Można zmienić miejsce rekurencji, wtedy najpierw wyliczy katalog, a potem jego katalogi:

KOD cpp:     UKRYJ  
void __fastcall TForm1::ScanDir(TStringGrid *StringGrid1, String Dir)
{
 TSearchRec sr;

 if(FindFirst(Dir + "*.*", faAnyFile, sr) == 0)
 {
   do
   {
    if( (sr.Name != ".") & (sr.Name != "..") )
    {
     if((sr.Attr & faDirectory) > 0)
     {
      WypelnijTabele(StringGrid1, sr.Name, 1);
      WypelnijTabele(StringGrid1, "Katalogi są", 2);
      WypelnijTabele(StringGrid1, Dir + sr.Name, 4);
     }
     else
     {
      WypelnijTabele(StringGrid1, sr.Name, 1);
      WypelnijTabele(StringGrid1, "Pliki są", 3);
     }

     WypelnijTabele(StringGrid1, (String)StringGrid1->RowCount, 0);
     StringGrid1->RowCount += 1;

     ScanDir(StringGrid1, Dir + sr.Name + "\\");
    }

    Application->ProcessMessages();
   }
   while (FindNext(sr) == 0);
   FindClose(sr);
 }
}


Wciąż jednak najpierw wylicza pierwszy katalog, a potem podkatalogi w tym katalogu. To niestety wiąże się z rekurencją. BY to zmienić, czyli najpierw wyliczyć wszystkie katalogi, potem podkatalogi w tych katalogach, trzeba by zrezygnować z rekurencji i wielokrotnie wywoływać funkcję skanującą dla każdego katalogu oddzielnie.

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
samurai-jerry
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez samurai-jerry » poniedziałek, 14 marca 2011, 16:52

Przepraszam, że troszkę z opóźnieniem odpisuję.
Jeśli chodzi o Twój kod Cyfrowy Baronie, to wszystko jest w porządku pod względem algorytmu rekurencji (tak jak napisałeś), lecz nie jest pod względem przyjętej funkcjonalności. Wytłumaczę na przykładzie o co mi chodzi.

Załóżmy że mamy takie drzewo katalogowe (spakowany plik z przykładem wysyłam w załączniku):
Dir_root - katalog główny na jakimś dysku, np. na dysku D. Pełna ścieżka do tego katalogu to: C:\Dir_root\
W katalogu Dir_root są katalogi: Dir_1 i Dir_2 oraz plik: file_1.txt - do każdego z nich można by przyporządkować takie ścieżki:
D:\Dir_root\Dir_1\
D:\Dir_root\Dir_2\
D:\Dir_root\file_1.txt

Dalej załóżmy, że:
W katalogu Dir_1 są same katalogi o nazwach: Dir_1_1 i Dir_1_2
Ich ścieżki dostępu to:
D:\Dir_root\Dir_1\Dir_1_1
D:\Dir_root\Dir_1\Dir_1_2

natomiast w katalogu Dir_2 są same pliki o nazwach: file_2_1.txt i file_2_2.txt
Ich ścieżki dostępu to:
D:\Dir_root\Dir_2\file_2_1.txt
D:\Dir_root\Dir_2\file_2_2.txt

Używając algorytmu, który podałeś otrzymalibyśmy wyniki mniej więcej takie (w załączniku wysyłam skan):
______________________________________________________________________________________
L.p. | Skanowany katalog | Są w nim katalogi? | Są w nim pliki? | Ścieżka do skanowanego katalogu |
------------------------------------------------------------------------------------------------------------------------
| Dir_1_1 | Katalogi są | | D:\Dir_root\Dir_1\Dir_1_1
------------------------------------------------------------------------------------------------------------------------
3 | Dir_1_2 | Katalogi są | | D:\Dir_root\Dir_1\Dir_1_2
------------------------------------------------------------------------------------------------------------------------
4 | Dir_1 | Katalogi są | | D:\Dir_root\Dir_1
------------------------------------------------------------------------------------------------------------------------
5 | | | Pliki są |
------------------------------------------------------------------------------------------------------------------------
6 | | | Pliki są |
------------------------------------------------------------------------------------------------------------------------
7 | Dir_2 | Katalogi są | | D:\Dir_root\Dir_2
------------------------------------------------------------------------------------------------------------------------
8 | | | Pliki są |
------------------------------------------------------------------------------------------------------------------------
9 | | | |
------------------------------------------------------------------------------------------------------------------------

Co się zgadza, a co nie:
Zgadza się: określenie czy w danej ścieżce znajdują się katalogi i (czy także, albo czy tylko) pliki

Co się nie zgadza:
Wypisywanie wyników istnienia katalogów lub/i plików powinno być wypisywane w jednej linii, natomiast jako nazwa katalogu powinna być wypisywana nazwa katalogu nadrzędnego a nie obecnego.

W odniesieniu do zaproponowanego z założenia katalogu tabelka powinna wyglądać mniej/więcej tak:

______________________________________________________________________________________
L.p. | Skanowany katalog | Są w nim katalogi? | Są w nim pliki? | Ścieżka do skanowanego katalogu |
------------------------------------------------------------------------------------------------------------------------
1 |-------Dir_root--------| Katalogi są----------| ---- Pliki są ----| D:\Dir_root
------------------------------------------------------------------------------------------------------------------------
2 |-------Dir_1-----------| Katalogi są---------|-------------------| D:\Dir_root\Dir_1
------------------------------------------------------------------------------------------------------------------------
3 |-------Dir_1_1--------|-----------------------|-------------------| D:\Dir_root\Dir_2
------------------------------------------------------------------------------------------------------------------------
4 |-------Dir_1_2 --------|-----------------------|-------------------| D:\Dir_root\Dir_2
------------------------------------------------------------------------------------------------------------------------
5 |-------Dir_2------------|-----------------------| ---- Pliki są ----| D:\Dir_root\Dir_2
------------------------------------------------------------------------------------------------------------------------

Oczywiście nie piszę tego tutaj po to, żeby wybrzydzać nad zaproponowanym przez Ciebie Cyfrowy Baronie rozwiązaniu (do głowy by mi nie przyszło!), jednak muszę po prostu popracować nad innym rozwiązaniem tego problemu.
Zgodnie z tym co napisałeś wcześniej będę starał się to rozwiązać wektorowo - to faktycznie bardzo dobre rozwiązanie (nie wiem czy nie jedyne). Mój algorytm wyglądałby w wolnym zapisie następująco:

1. Wypisz wszystkie katalogi podrzędne (oczywiście bez podkatalogów) z katalogu Dir_root i zapamiętaj je w buforze pamięci.
2. Pobierz pierwszy zapamiętany katalog i wypisz jego katalogi do bufora pamięci
3. Powtarzaj krok 2 tak długo, aż napotkasz na koniec gałęzi drzewa katalogów (brak podkatalogów w ostatnim skanowanym katalogu).
4. Przejdź do kolejnego katalogu i przeskanuj go zgodnie z algorytmem punktu 2.
5. Powtarzaj punkt 4 tak długo, aż napotkasz na koniec wypisanych katalogów z katalogu Dir_root.

To tak na razie wygląda ten algorytm - pewnie w trakcie nieco go zmienię, chociaż pewnie też nie za bardzo. ;)
Jako bufora pamięci zamierzam tu użyć tablicy dwuwymiarowej złożonej z tablic typu <vector> - zobaczę co da się zrobić...

Dziękuję za dotychczasową pomoc! :)

Gdybyś wpadł na jakiś pomysł Cyfrowy Baronie, albo Ktokolwiek z pozostałych tutaj forumowiczów to w dalszym ciągu bardzo proszę o pomoc.
Gdy z kolei ja znajdę rozwiązanie to oczywiście wkleję tutaj swój kod.

Pozdrawiam serdecznie! samurai-jerry
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
"No pain no gain" - Scorpions
Avatar użytkownika
samurai-jerry
Bladawiec
Bladawiec
 
Posty: 24
Dołączył(a): sobota, 19 lutego 2011, 19:04
Podziękował : 15
Otrzymał podziękowań: 0
System operacyjny: W98,W2K,WXP
Kompilator: Borland C++ Builder v6.0 Personal
wxDevCpp v.6.9
ChromeIDE+Masm32
KDevelop
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez Cyfrowy Baron » wtorek, 15 marca 2011, 13:16

W pętli sprawdzany jest tylko jeden element, czyli tutaj albo katalog, albo plik, dlatego rekurencja nic tutaj nie pomaga, a wręcz przeszkadza. Jak można rozwiązać problem? Przychodzi mi do głowy tylko jedne sposób, trzeba wyliczać po kolei najpierw katalogi w katalogu głównym, potem w jego podkatalogach itd. To będzie bardzo niewydajny kod.

samurai-jerry napisał(a):natomiast jako nazwa katalogu powinna być wypisywana nazwa katalogu nadrzędnego a nie obecnego.


Chyba chodziło Tobie o katalog podrzędny - podkatalog jest podrzędny względem katalogu w którym się znajduje...

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
samurai-jerry
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez samurai-jerry » czwartek, 17 marca 2011, 13:00

Okey, póki co wymyśliłem coś takiego co poniżej.
Aplikacja czyta dany katalog (ścieżkę + katalog), który został wczytany w okienku nazwanego "Skanuj katalog".
Skanuje ten katalog, tzn.
- wypisuje wszystkie podkatalogi do jednowymiarowej tablicy vector (nazwanej lista)
- przekształca tablicę jednowymiarową w dwuwymiarową w taki sposób, żeby była informacja o głębokości danego podkatalogu w stosunku do katalogu, który pełni rolę korzenia w tymże drzewie katalogów
(nazwa tablicy dwuwymiarowej = dir_name)
- przepisuje tablicę dwuwymiarową do tablicy StringGrid1 w taki sposób w jaki widzi ją tablica dwuwymiarowa

nagłówek pliku:
KOD cpp:     UKRYJ  
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Grids.hpp>
#include <vector>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TPanel *Panel1;
        TButton *Button1;
        TStringGrid *StringGrid1;
        TEdit *Edit1;
        TLabel *Label1;
        TLabel *Label2;
        TButton *Button2;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall FormCreate(TObject *Sender);
        void __fastcall Button2Click(TObject *Sender);
        void __fastcall Edit1KeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift);
private:        // User declarations
public:         // User declarations
        __fastcall TForm1(TComponent* Owner);
        void __fastcall FindDir(String Dir);
        int  __fastcall CheckDeep(String path);
        void __fastcall List2Matrix();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
 


plik źródłowy:
KOD cpp:     UKRYJ  
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

using std::vector;

// jednowymiarowa tablica vector
vector <String> lista;

// dwuwymiarowa tablica vector
vector < vector<String> > dir_name;

unsigned int deep_i, count_i;
unsigned int deep_max, count_max;

TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}

//---------------------------------------------------------------------------
// funkcja wypisująca wszystkie podkatalogi z danego
// katalogu
// autor: Cyfrowy Baron,
// strona autora: http://programowanie.cal.pl/cyfbar/
void __fastcall TForm1::FindDir(String Dir)
{
TSearchRec sr;
if (FindFirst(Dir + "*.*", faAnyFile, sr) == 0)
   {
   do
     {
     if (((sr.Attr & faDirectory) > 0) & (sr.Name != ".") & (sr.Name != ".."))
        {
        FindDir(Dir + sr.Name + "\\");
        lista.push_back(Dir + sr.Name);
        }
     }
     while(FindNext(sr) == 0);
     FindClose(sr);
   }
}

//---------------------------------------------------------------------------
// algorytm sprawdzania zagłębienia danego podkatalogu
// w drzewie przeszukiwanego katalogu
int __fastcall TForm1::CheckDeep(String path)
{
unsigned int deep;
deep=0;
while (path.Pos("\\")>0)
      {
      path=path.Delete(1,path.Pos("\\"));
      deep++;
      }
return deep;
}

//---------------------------------------------------------------------------
// kopiowanie tablicy jednowymiarowej
// (która zawiera tylko listę katalogów)
// do
// tablicy dwuwymiarowej
// (która dodatkowo zawiera informację o
// indeksie danego podkatalogu w przeszukiwanym katalogu)
void __fastcall TForm1::List2Matrix()
{
deep_max=0;
count_max=0;

// szukanie deep_max i count_max w celu określenia
// rozmiaru matrycy (tablicy) dwuwymiarowej
for (count_i=0; count_i<lista.size(); count_i++)
    {
    deep_i=CheckDeep(lista[count_i]);
    count_max++;
    if (deep_max<deep_i)
       {
       deep_max=deep_i;
       if (count_max>count_i)
          {
          count_max--;
          }
       }
    }

// przygotowanie rozmiaru dla tablicy dwuwymiarowej
// rozmiar musi być o jeden większy niż
// ten podawany z size()
deep_max=deep_max+1;
count_max=count_max+1;

// ustawienie maksymalnego rozmiaru dla deep_i
dir_name.resize(deep_max);
for (deep_i=0; deep_i<deep_max; deep_i++)
    {
    // ustawienie max. rozmiaru dla deep_i
    dir_name[deep_i].resize(count_max);
    }

// wypełnienie tablicy dwuwymiarowej wartościami
// z tabllicy jednowymiarowej
deep_i=0;
count_i=0;
for (unsigned int i=0; i<lista.size(); i++)
    {
    deep_i=CheckDeep(lista[i]);
    dir_name[deep_i][count_i]=lista[i];
    count_i++;
    }
}

//---------------------------------------------------------------------------
// algorytm wyszukiwania wszystkich podkatalogów w danym katalogu
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// czyszczenie tabeli StringGrid
for (int x=0; x<StringGrid1->ColCount; x++)
    {
    for (int y=0; y<StringGrid1->RowCount; y++)
        {
        StringGrid1->Rows[y]->Clear();
        }
    StringGrid1->Cols[x]->Clear();
    }
StringGrid1->ColCount=0;
StringGrid1->RowCount=0;

lista.clear();       // czyszczenie tablicy jednowymiarowej
FindDir(Edit1->Text);// wypełnianie tablicy jednowymiarowej
List2Matrix();       // wypełnianie tablicy dwuwymiarowej

// wypełnianie tabeli StringGrid1 w taki sposób,
// w jaki sposób widzi ją tablica dwuwymiarowa

for (unsigned int x1=0; x1<deep_max; x1++)
    {
    for (unsigned int y1=0; y1<count_max; y1++)
        {
        if (dir_name[x1][y1]!="")
           {
           StringGrid1->Cells[x1][y1]=dir_name[x1][y1];
           StringGrid1->RowCount++;
           }
        }
    StringGrid1->ColCount++;
    }
StringGrid1->RowCount--;
StringGrid1->ColCount--;
}

//---------------------------------------------------------------------------
// generowane raz po uaktywnieniu aplikacji
// inicjalizacja zmiennych
void __fastcall TForm1::FormCreate(TObject *Sender)
{
deep_i=0;
count_i=0;
Edit1->Text="D:\\Dir_root\\";
}

//---------------------------------------------------------------------------
// zamknięcie aplikacji klawiszem Zamknij
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Application->Terminate();
}

//---------------------------------------------------------------------------
// żeby po wprowadzeniu tekstu można było za pomocą
// klawisza ENTER od razu uaktywnić algorytm
void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
if (Key == VK_RETURN)
  {
  Button1->Click();
  }
}
 


W obecnym kodzie (który co prawda jeszcze nie spełnia założeń, ale już niedługo) denerwują mnie dwie rzeczy, mianowicie:
1. Dlaczego trzeba podawać rozmiar tablicy vector (ten do przeskalowania rozmiaru) o jeden większy niż ten pobrany ze zmiennej deep_max, która przecież ustala go na podstawie tego co wykryje w pętli.. No chyba, że gdzieś jest błąd - czego oczywiście nie wykluczam, ale nie potrafię tego wykryć.
2. Sprawa z dodawaniem nowej kolumny/wiersza do StringGrid1 i to, żeby tabelka była wyświetlona we właściwej postaci trzeba na samym końcu zastosować instrukcje:
KOD cpp:     UKRYJ  
StringGrid1->RowCount--;
StringGrid1->ColCount--;
 


Jeszcze jedna sprawa - całkiem prosta, ale z tego wszystkiego zapomniałem jak to się robi, tzn.
Jak dowiedzieć się, czy dany podkatalog, dajmy na to (z mojego przykładu) Dir_1 zawiera jakieś podkatalogi, albo pliki. Chodzi mi o prosty algorytm typu
KOD cpp:     UKRYJ  
if ("Dir_1"==zawiera_podkatalogi)
   {
   ShowMessage("Dir_1 zawiera podkatalogi");
   }
if ("Dir_1"==zawiera_pliki)
   {
   ShowMessage("Dir_1 zawiera pliki");
   }
if ((!"Dir_1"==zawiera_pliki)&&(!"Dir_1"==zawiera_katalogi))
   {
   ShowMessage("Dir_1 nie zawiera ani plików ani katalogów");
   }
 

Oczywiście zakładam, że dany podkatalog może:
- zawierać TYLKO pliki
- zawierać TYLKO katalogi
- zawiera pliki i katalogi
- nie zawiera ani plików ani katalogów

Proszę! Czy ktoś może mi pomóc z tym ostatnim algorytmem? - Z góry WIELKIE dzięki!!!!

Pozdrawiam! samurai-jerry
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
"No pain no gain" - Scorpions
Avatar użytkownika
samurai-jerry
Bladawiec
Bladawiec
 
Posty: 24
Dołączył(a): sobota, 19 lutego 2011, 19:04
Podziękował : 15
Otrzymał podziękowań: 0
System operacyjny: W98,W2K,WXP
Kompilator: Borland C++ Builder v6.0 Personal
wxDevCpp v.6.9
ChromeIDE+Masm32
KDevelop
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez Cyfrowy Baron » czwartek, 17 marca 2011, 13:17

samurai-jerry napisał(a):
KOD cpp:     UKRYJ  
using std::vector;


Zrób tak:
KOD cpp:     UKRYJ  
using namespace std;


wtedy przestrzeń nazw std będzie się tyczyć wszystkich obiektów, które wykorzystujesz w programie, a nie tylko vector'a.



samurai-jerry napisał(a):Jak dowiedzieć się, czy dany podkatalog, dajmy na to (z mojego przykładu) Dir_1 zawiera jakieś podkatalogi, albo pliki. Chodzi mi o prosty algorytm typu


Dokładnie tak samo jak sprawdzasz, czy katalog główny zawiera jakiś katalog, czyli wyliczając wszystko co znajduje się w tym podkatalogu. To ta sama funkcja przeszukiwania, nie ma tutaj żadnej drogi na skróty.

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
samurai-jerry
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez samurai-jerry » czwartek, 17 marca 2011, 15:57

Cyfrowy Baron napisał(a):Dokładnie tak samo jak sprawdzasz, czy katalog główny zawiera jakiś katalog, czyli wyliczając wszystko co znajduje się w tym podkatalogu. To ta sama funkcja przeszukiwania, nie ma tutaj żadnej drogi na skróty.


Nie wiem co to znaczy dokładnie "Dokładnie" ;) ale u mnie zadziałało gdy dodałem poniższą funkcję:
KOD cpp:     UKRYJ  
void __fastcall TForm1::IsDirFileExists(String path)
{
TSearchRec sr;
String info="";
info="W katalogu: "+path;

bool nodirsfiles=true;

// sprawdzenie czy są katalogi
if (FindFirst(path + "\\*.*", faAnyFile, sr) == 0)
   {
   do
     {
     if (nodirsfiles==true)
        {
        if ((sr.Attr & faDirectory) == sr.Attr)
           {
           if (sr.Name!="." && sr.Name!="..")
              {
              info=info+"\nsą katalogi";
              nodirsfiles=false;
              }
           }
        }
     } // do while
     while (FindNext(sr) == 0);
   FindClose(sr);
   }

// sprawdzenie czy są pliki
if (FindFirst(path + "\\*.*", faAnyFile, sr) == 0)
   {
   do
     {
     if (nodirsfiles==true)
        {
        if ((sr.Attr & faArchive) == sr.Attr)
           {
           if (sr.Name!="." && sr.Name!="..")
              {
              info=info+"\nsą pliki";
              nodirsfiles=false;
              }
           }
        }
     } // do while
   while (FindNext(sr) == 0);
   FindClose(sr);
   }

if (nodirsfiles==true)
   {
   info=info+"\nbrak plików i katalogów";
   }

// komunikat końcowy
ShowMessage(info);
}
 


To znaczy to jest kod, który spełnia w 100% wymagania jakie ja postawiłem dla swojej aplikacji, ale być może można go uprościć.
Cały kod przesyłam w załączniku.

Dzięki Cyfrowy Baronie za tą radę, żeby wykorzystać tablicę typu vector :) - super sprawa. :D :geek: :D Dziękuję.

Problem opisywany w tym poście uważam za rozwiązany. :D :D :D

Pozdrawiam! samurai-jerry
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
"No pain no gain" - Scorpions
Avatar użytkownika
samurai-jerry
Bladawiec
Bladawiec
 
Posty: 24
Dołączył(a): sobota, 19 lutego 2011, 19:04
Podziękował : 15
Otrzymał podziękowań: 0
System operacyjny: W98,W2K,WXP
Kompilator: Borland C++ Builder v6.0 Personal
wxDevCpp v.6.9
ChromeIDE+Masm32
KDevelop
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez Cyfrowy Baron » czwartek, 17 marca 2011, 16:25

samurai-jerry napisał(a):Nie wiem co to znaczy dokładnie "Dokładnie" ;) ale u mnie zadziałało gdy dodałem poniższą funkcję:


To znaczy mniej więcej to co zrobiłeś, tyle że dwukrotnie wywołałeś funkcję FindFirst w celu przeszukania katalogów i podkatalogów. Ja bym pomyślał nad taką optymalizacją tego kodu, by upchnąć go w jedną pętlę FindFirst wtedy kod byłby wydajniejszy, ale jeżeli Tobie to wystarcza, to nie ja nie widzę problemu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez samurai-jerry » czwartek, 17 marca 2011, 17:26

Hurra :D :D :D - nie wiem jak mi się to udało, bo przedtem robiłem dokładnie tak samo, ale teraz zadziałało! :D
tzn. jedno wywołanie pętli FindFirst + to wszystko co powyżej opisane, a dodatkowo funkcja działa w taki sposób, że można ją wywołać w zasadzie z każdego kodu! :D :D :D

Oto kod:
KOD cpp:     UKRYJ  
char __fastcall TForm1::IsDirFileExists(String path)
{
// możliwe wartości return info:
// k - są tylko katalogi   ( k=katalogi )
// p - są tylko pliki      ( p=pliki    )
// w - są katalogi i pliki ( w=wszystko )
// n - brak                ( n=nic      )
TSearchRec sr;
char info='n'; // domyślnie: brak plików i katalogów

if (FindFirst(path + "\\*.*", faAnyFile, sr) == 0)
   {
   do
     {
     if (info=='n')
        {
        // sprawdzenie czy są katalogi
        if ((sr.Attr & faDirectory) == sr.Attr)
           {
           if (sr.Name!="." && sr.Name!="..")
              {
              info='k'; // są katalogi
              }
           }

        // sprawdzenie czy są pliki
        if ((sr.Attr & faArchive) == sr.Attr)
           {
           if (sr.Name!="." && sr.Name!="..")
              {
              // sprawdzenie czy są także katalogi
              if (info=='k')
                 {
                 info='w'; // są i katalogi i pliki
                 }
                 else
                     {
                     info='p'; // są TYLKO pliki
                     }
              }
           }
        }
     } // do while
     while (FindNext(sr) == 0);
   FindClose(sr);
   }

// ten switch można pominąć albo zastosować do sprawdzenia
/*
switch (info)
       {
       case 'k' : { ShowMessage("W katalogu: "+path+" są TYLKO katalogi"); } break;
       case 'p' : { ShowMessage("W katalogu: "+path+" są TYLKO pliki"); } break;
       case 'w' : { ShowMessage("W katalogu: "+path+" są pliki i katalogi"); } break;
       case 'n' : { ShowMessage("W katalogu: "+path+" brak plików i katalogów"); } break;
       }
*/


// komunikat końcowy
return info;
}
 


Dzięki za rady Cyfrowy Baronie! 8-) :D

Pozdrawiam! samurai-jerry
"No pain no gain" - Scorpions
Avatar użytkownika
samurai-jerry
Bladawiec
Bladawiec
 
Posty: 24
Dołączył(a): sobota, 19 lutego 2011, 19:04
Podziękował : 15
Otrzymał podziękowań: 0
System operacyjny: W98,W2K,WXP
Kompilator: Borland C++ Builder v6.0 Personal
wxDevCpp v.6.9
ChromeIDE+Masm32
KDevelop
Gadu Gadu: 0
    Windows XPFirefox

Re: BCB6, skanowanie katalogu z dysku + zapis do StringGrid

Nowy postprzez samurai-jerry » środa, 10 sierpnia 2011, 15:20

W moim kodzie był błąd... :/
Przepraszam, jeśli ktoś korzystał i tracił nerwy. Ja trochę późno wykryłem ten błąd.

Było (kod błędny):
KOD cpp:     UKRYJ  
        // sprawdzenie czy są katalogi
        if ((sr.Attr & faDirectory) == sr.Attr)
 


Powinno być (kod poprawny):
KOD cpp:     UKRYJ  
        // sprawdzenie czy są katalogi
        if ((sr.Attr & faDirectory) > 0 )
 


Pozdrawiam! samurai-jerry
"No pain no gain" - Scorpions
Avatar użytkownika
samurai-jerry
Bladawiec
Bladawiec
 
Posty: 24
Dołączył(a): sobota, 19 lutego 2011, 19:04
Podziękował : 15
Otrzymał podziękowań: 0
System operacyjny: W98,W2K,WXP
Kompilator: Borland C++ Builder v6.0 Personal
wxDevCpp v.6.9
ChromeIDE+Masm32
KDevelop
Gadu Gadu: 0
    Windows XPFirefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Bazy danych

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 2 gości

cron