Przeszukiwanie ścieżki w poszukiwaniu plików za pomocą funkcji _findfirst i _findnext

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 5255 razy

Pobawiliśmy się już w zapisywanie i odczytywanie danych z i do pliku, teraz kolej przyszła pobuszować w katalogach i nauczyć się znajdowania plików i folderów zawartych w danej lokalizacji. Do tego celu można posłużyć się funkcjami _findfirst oraz _findnext, które umożliwiają przeszukiwanie danej ścieżki według podanego filtra przeszukiwania. Oto przykłady filtrów, wraz z ich opisem:

Oto przykładowy mały programik przeszukujący daną lokalizację oraz podfoldery i wyświetlająca katalogi i nazwy plików, w których dany plik został znaleziony:

#include <iostream> #include <vector> #include <string> #include <windows.h> #include <io.h> using namespace std; void searchFile(string path, string filtr){ _finddata_t f; intptr_t r; // przeszukiwanie podfolderów string searching_filtr = path; // tworzę filtr przeszukiwania folderów searching_filtr += "*"; // na końcu potrzebna jest * if((r=_findfirst(searching_filtr.c_str(),&f))>0){ // znajdowanie pierwszego folderu (to zawsze jest . while(!_findnext(r,&f)){ if(strcmp(f.name, "..")){ // drugi to .. if(f.attrib & _A_SUBDIR){ // gdy dany element jest folderem to string p2 = path; // kopię ścieżki głównej robię p2 += f.name; // dodaję do tego nazwę folderu p2 += char(92); // dodaję na końcu searchFile(p2, filtr); // przeszukuję nową lokalizację } } } } _findclose(r); // zamykam przeszukiwanie // wyszukiwanie plików według podanego filtra searching_filtr = path; // tworzę ścieżkę dla filtra searching_filtr += filtr; // dodaję na koniec filtr if((r=_findfirst(searching_filtr.c_str(),&f))>0){ // piersze przeszukiwanie do{ // kolejne przeszukiwania if(!(f.attrib & _A_SUBDIR)){ // jak nie jest to folder cout<<path<<"t"<<f.name<<endl; // wypisuję nazwę znalezionego pliku } }while(!_findnext(r,&f)); } _findclose(r); // zamykam przeszukiwanie } int main(int size, char** pt){ setlocale(LC_CTYPE,"Polish"); // polskie znaki string path = pt[0]; // wyciągam ścieżkę z nazwą programu string filtr = "*.*"; // to będzie filtr przeszukiwania path.erase(path.begin() + path.find_last_of(char(92),string::npos) + 1,path.end()); // wydziabuję ścieżkę dostępu do lokalizacji programu cout<<"Przeszukiwanie ścieżki: \apos"<<path<<"\apos z filtrem wyszukiwania \apos"<<filtr<<"\apos"<<endl<<endl; // wyświetlam searchFile(path,filtr); cout<<endl<<endl<<"Wciśnij enter, aby zamknąć program..."; cin.get(); return 0; }

Warto przyjrzeć się nieco dokładniej strukturze _finddata_t, która ma następującą postać:

struct _finddata64i32_t { unsigned attrib; // atrybuty pliku __time64_t time_create; // czas utworzenia pliku __time64_t time_access; // czas ostatniego dostępu do pliku __time64_t time_write; // czas ostatniego nadpisania pliku _fsize_t size; // rozmiar pliku char name[260]; // nazwa pliku (maksymalnie 259 znaków bo jeden jest przeznaczony na NULL) }; typedef _finddata64i32_t _finddata_t;

W zależności od systemu może stosowane są nieco inne deklaracje tej samej struktury, stąd też zapis na końcu typedef _finddata64i32_t _finddata_t;.

Warto przyjrzeć się polu struktury attrib, dla którego ustawienia bitów mówią o rodzaju i dostępie do danego pliku:

#define _A_NORMAL 0x00 // normalny plik - bez zakazu odczytu/zapisu #define _A_RDONLY 0x01 // tylko do odczytu #define _A_HIDDEN 0x02 // ukryty #define _A_SYSTEM 0x04 // systemowy #define _A_SUBDIR 0x10 // podfolder #define _A_ARCH 0x20 // archiwalny

Ponieważ dany typ pliku czy folderu może mieć kilka różnych atrybutów, konieczne jest wykorzystanie operatora koniunkcji bitowej & (czyli AND). Dla folderów taki test będzie wyglądał następująco:

if(f.attrib & _A_SUBDIR){ cout<<"To jest folder!!!"<<endl; }

Powyższe sprawdzenie zostało już oczywiście wykorzystane w programie.

Funkcje _findfirst i _findnext są nieco przestarzałe i nie obsługują szerokich znaków (typ wchar_t), co w konsekwencji może doprowadzić, że plik zawierający w nazwie znaki kodowania np. cyrylicy czy alfabetu greckiego nie będą poprawnie obsługiwane. Z tego względu warto też zwrócić uwagę na funkcje _wfindfirst oraz _wfindnext.
Propozycje książek