API Windows / Gestion de fichiers
Résolu
Telnaz
-
Telnaz -
Telnaz -
Bonjour, je créé un de mes premiers programmes sur Visual Studio pour un projet. Je dois coder celui-ci via le langage C et l'API Windows uniquement. J'ai déjà bien avancé, avec différentes recherches / aides.
A présent, je bloque sur quelque chose ...
J'essaie de coder une recherche de codes dans plusieurs fichiers, ce code est compris entre deux balises que j'appelle <A> et </A>.
Pour l'instant je bloque sur le fait de rechercher et lister tous les fichiers, qui sont contenus dans plusieurs sous-dossiers, différentes arborescences...
Est-ce que vous connaissez des fonctions ou autre méthode permettant cela ? Via l'API Windows ...
Merci
A présent, je bloque sur quelque chose ...
J'essaie de coder une recherche de codes dans plusieurs fichiers, ce code est compris entre deux balises que j'appelle <A> et </A>.
Pour l'instant je bloque sur le fait de rechercher et lister tous les fichiers, qui sont contenus dans plusieurs sous-dossiers, différentes arborescences...
Est-ce que vous connaissez des fonctions ou autre méthode permettant cela ? Via l'API Windows ...
Merci
A voir également:
- API Windows / Gestion de fichiers
- Clé de produit windows 10 gratuit - Guide
- Montage video windows - Guide
- Windows ne démarre pas - Guide
- Windows movie maker - Télécharger - Montage & Édition
- Logiciel gestion photo gratuit windows - Guide
12 réponses
Salut Telnaz,
L'API Windows comporte la fonction FindFirstFile() qui permet de retourner le premier fichier matchant l'argument de recherche et FindNextFile() qui permet de retourner le reste.
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilea
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilea
https://docs.microsoft.com/en-us/windows/win32/fileio/listing-the-files-in-a-directory
Dal
L'API Windows comporte la fonction FindFirstFile() qui permet de retourner le premier fichier matchant l'argument de recherche et FindNextFile() qui permet de retourner le reste.
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilea
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilea
https://docs.microsoft.com/en-us/windows/win32/fileio/listing-the-files-in-a-directory
Dal
Salut, merci pour ta réponse.
En effet, j'ai déjà utilisé ces fonctions ... D'ailleurs, j'arrive bien à lister les fichiers et sous-dossier du dossier courant. Par contre, je ne sais pas comment effectuer cette analyse de façon récursive, c'est-à-dire également lister tous les fichiers, compris dans les sous-dossiers ...
bufferCheminSousDossier : chemin absolu du dossier courant (ou j'effectue la recherche de fichiers)
Voici mon code :
En effet, j'ai déjà utilisé ces fonctions ... D'ailleurs, j'arrive bien à lister les fichiers et sous-dossier du dossier courant. Par contre, je ne sais pas comment effectuer cette analyse de façon récursive, c'est-à-dire également lister tous les fichiers, compris dans les sous-dossiers ...
bufferCheminSousDossier : chemin absolu du dossier courant (ou j'effectue la recherche de fichiers)
Voici mon code :
//hedit sont les formulaires remplis si les boutons correspondants sont actionnés
if (hEditJ !=0 && hEditI !=0)
{
strcat(bufferCheminSousDossier,"\\*");
hFind2 = FindFirstFile(bufferCheminSousDossier, &ffd);
if (INVALID_HANDLE_VALUE == hFind2)
{
DisplayErrorBox(TEXT("FindFirstFile"));
return dwError;
}
do {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
Trouve =1;
MessageBox(NULL, ffd.cFileName , "test", MB_ICONWARNING | MB_OK);
}
else
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
MessageBox(NULL, ffd.cFileName , "test", MB_ICONWARNING | MB_OK);
SendMessage(hEditK, WM_SETTEXT, 0, (long)filesize.QuadPart);
}
} while (FindNextFile(hFind2, &ffd) !=0);
if (Trouve == 0)
{
MessageBox(NULL, "Il n'existe aucun fichier qui correspond à la demande", "Erreur", MB_ICONWARNING | MB_OK);
}
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
msgboxID = MessageBox(NULL, "Erreur", "Erreur", MB_ICONWARNING | MB_OK);
}
FindClose(hFind);
return dwError;
}
Tu peux t'inspirer de ce code :
https://stackoverflow.com/questions/2038912/how-to-recursively-traverse-directories-in-c-on-windows/2043959#2043959
https://stackoverflow.com/questions/2038912/how-to-recursively-traverse-directories-in-c-on-windows/2043959#2043959
J'ai repris ce même code, cela me fait pareil ... il n'y a pas de procédure récursive :
main.c :
fonction.c :
main.c :
// Code présent au-dessus
if (hEditJ !=0 && hEditI !=0)
{
FindFilesRecursively(_T(bufferCheminSousDossier), _T("*."));
}
// ..........
fonction.c :
HANDLE hFind3 = INVALID_HANDLE_VALUE;
TCHAR szFullPattern[MAX_PATH];
void FindFilesRecursively(LPCTSTR lpFolder, LPCTSTR lpFilePattern)
{
PathCombine(szFullPattern, lpFolder, _T("*"));
hFind3= FindFirstFile(szFullPattern, &ffd);
if(hFind3 != INVALID_HANDLE_VALUE)
{
do
{
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
PathCombine(szFullPattern, lpFolder, ffd.cFileName);
FindFilesRecursively(szFullPattern, lpFilePattern);
}
} while(FindNextFile(hFind3, &ffd));
FindClose(hFind3);
}
PathCombine(szFullPattern, lpFolder, lpFilePattern);
hFind3 = FindFirstFile(szFullPattern, &ffd);
if(hFind3 != INVALID_HANDLE_VALUE)
{
do
{
if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
PathCombine(szFullPattern, lpFolder, ffd.cFileName);
MessageBox(NULL, szFullPattern , "Liste", MB_OK);
}
} while(FindNextFile(hFind3, &ffd));
FindClose(hFind3);
}
}
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Bonjour Telnaz,
Et comme ça ? (scan_dir s'appelle elle-même recursivement) :
Et comme ça ? (scan_dir s'appelle elle-même recursivement) :
#include <windows.h> void scan_dir(char *path) { WIN32_FIND_DATA fd; void *dir; char newp[80], search_path[80], *filename; strlwr(path); strcpy(search_path, path); strcat(search_path, "*.*"); dir = FindFirstFile(search_path, &fd); // . DOS FindNextFile(dir, &fd); // .. DOS while(FindNextFile(dir, &fd)) { if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) // file { filename = fd.cFileName; } else //directory { strcpy(newp, path); strcat(newp, fd.cFileName); strcat(newp, "\\"); scan_dir(newp); } } FindClose(dir); }
Non cela fonctionne mal avec mon code, j'ai beaucoup d'erreur ...
Pour revenir au code précédent, j'ai remarqué que le valeur du szFullPattern, lorsque l'on cherche les fichiers correspondants, ne changeait pas. C'est-à-dire, il ne suit pas la procédure récursive qui est faite lors de la recherche des dossiers ...
Je pense donc qu'il manque une boucle à ce niveau là ... Mais je n'ai pas réussi à améliorer la chose
Pour revenir au code précédent, j'ai remarqué que le valeur du szFullPattern, lorsque l'on cherche les fichiers correspondants, ne changeait pas. C'est-à-dire, il ne suit pas la procédure récursive qui est faite lors de la recherche des dossiers ...
Je pense donc qu'il manque une boucle à ce niveau là ... Mais je n'ai pas réussi à améliorer la chose
Ah OK,
Je proposais cette fonction récursive car je m'en servais souvent dans divers projets pour explorer une arborescence de répertoires (en profondeur d'abord) et elle fonctionnait très bien
Evidemment, j'ai simplifié, dans le if où on détecte que c'est un fichier, je faisais quelque chose de filename ......
J'y avais même inclus les fonctions setjump() et longjump() pour re sauter à mon programme principal dès que j'avais trouvé le fichier recherché, et éviter tous les dépilages des appels successifs de la fonction
Je proposais cette fonction récursive car je m'en servais souvent dans divers projets pour explorer une arborescence de répertoires (en profondeur d'abord) et elle fonctionnait très bien
Evidemment, j'ai simplifié, dans le if où on détecte que c'est un fichier, je faisais quelque chose de filename ......
J'y avais même inclus les fonctions setjump() et longjump() pour re sauter à mon programme principal dès que j'avais trouvé le fichier recherché, et éviter tous les dépilages des appels successifs de la fonction
J'ai corrigé les nombreux soucis de compatibilité ...
Mais, après compilation et lancement de l'interface, je n'ai rien qui est renvoyé lors de l'exécution de la fonction.
J'ai, un doute, quand j'appelle la fonction dans le main.c, j'écris :
scan_dir(bufferCheminSousDossier);
?
bufferCheminSousDossier est le chemin absolu du sous dossier que je dois analyser
Mais, après compilation et lancement de l'interface, je n'ai rien qui est renvoyé lors de l'exécution de la fonction.
J'ai, un doute, quand j'appelle la fonction dans le main.c, j'écris :
scan_dir(bufferCheminSousDossier);
?
bufferCheminSousDossier est le chemin absolu du sous dossier que je dois analyser
Comme je te l'expliquais, j'ai simplifié pour montrer la structure, donc il ne se passe pas grand chose si tu à copié ma fonction telle quelle
Par exemple, dans un projet, je stockais le nom du fichier trouvé dans un fichier texte:
l'appel était comme ceci:
Par exemple, dans un projet, je stockais le nom du fichier trouvé dans un fichier texte:
if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) // file { ................ fprintf(fp, "%s%s\n",path, filename); } else { //répertoire ........ }
l'appel était comme ceci:
scan_dir('C:\\phil\\resultat\\');
ah!
attend voir, ce ne serait pas plutôt:
avec double quotes
(je suis en train de faire du Python, et là c'est la même chose, mais pas en C)
attend voir, ce ne serait pas plutôt:
scan_dir("D:\\MA_atp\\");
avec double quotes
(je suis en train de faire du Python, et là c'est la même chose, mais pas en C)
ok, mais tu as bien mis des double quotes pour re tester ??
too many characters in character constant
ça venait bien de l'emploi de simple quotes
Sinon, bizarre .... si il n'entre pas dans la boucle, c'est que FindNextFile(dir, &fd) renvoi false, donc qu'il ne trouve
rien comme fichiers ou répertoires dans dir
too many characters in character constant
ça venait bien de l'emploi de simple quotes
Sinon, bizarre .... si il n'entre pas dans la boucle, c'est que FindNextFile(dir, &fd) renvoi false, donc qu'il ne trouve
rien comme fichiers ou répertoires dans dir
Oui oui ne t'inquiète pas ... désolé j'oublie de tout te préciser mais c'est que j'ai fais pas mal de changements...
Aux dernières nouvelles, j'essaie de comprendre pourquoi il n'analyse pas les fichiers...
J'ai vérifié que la variable path comprenait bien le chemin, mais ensuite ça n'a pas l'air de fonctionner
Aux dernières nouvelles, j'essaie de comprendre pourquoi il n'analyse pas les fichiers...
J'ai vérifié que la variable path comprenait bien le chemin, mais ensuite ça n'a pas l'air de fonctionner
Salut Telnaz,
Je suis sous Linux habituellement, alors il m'est difficile de tester les codes Win32.
Le code posté sur SO boucle sur le même répertoire racine et j'ai la flemme de le déboguer tellement il comporte de code à la sauce MS.
Alors en voilà un autre, qui est fortement inspiré de celui posté dans ce fil https://arstechnica.com/civis/viewtopic.php?t=817827 par earl.
Ce code parcourt bien les répertoires. Il évite les entrées "." qui correspondent au répertoire courant et ".." qui correspond au répertoire parent et chez moi, il liste bien les 58 Fichiers contenus dans 26 Dossiers situés dans un répertoire qui se trouve à la racine de C:\ et qui s'appelle "Drivers".
Dal
Je suis sous Linux habituellement, alors il m'est difficile de tester les codes Win32.
Le code posté sur SO boucle sur le même répertoire racine et j'ai la flemme de le déboguer tellement il comporte de code à la sauce MS.
Alors en voilà un autre, qui est fortement inspiré de celui posté dans ce fil https://arstechnica.com/civis/viewtopic.php?t=817827 par earl.
#include <stdio.h> #include <windows.h> void recursively_list_files(char * dir) { HANDLE hFind; WIN32_FIND_DATA fd; char path[MAX_PATH + 1]; sprintf(path, "%s\\*", dir); printf("---- dans le repertoire %s ----\n\n", dir); if ((hFind = FindFirstFile(path, &fd)) == INVALID_HANDLE_VALUE) { printf("Erreur FindFirstFIle sur %s\n", path); exit(1); } while(1) { if ((strcmp(".", fd.cFileName) !=0) && (strcmp("..", fd.cFileName) != 0)) { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { /* c'est un dossier */ sprintf(path, "%s\\%s", dir, fd.cFileName); recursively_list_files(path); } else { /* c'est un fichier */ printf("fichier : %s\n", fd.cFileName); } } if (!FindNextFile(hFind, &fd)) break; } if (GetLastError() != ERROR_NO_MORE_FILES) { printf("Erreur FindNextFile - dans %s\n", path); exit(1); } if (FindClose(hFind) == FALSE) { printf("Erreur FindClose\n"); exit(1); } } int main(void) { /* sur mon disque C: j'ai un répertoire Drivers avec 58 Fichiers dans 26 Dossiers */ recursively_list_files("C:\\Drivers"); return 0; }
Ce code parcourt bien les répertoires. Il évite les entrées "." qui correspondent au répertoire courant et ".." qui correspond au répertoire parent et chez moi, il liste bien les 58 Fichiers contenus dans 26 Dossiers situés dans un répertoire qui se trouve à la racine de C:\ et qui s'appelle "Drivers".
---- dans le repertoire C:\Drivers ---- ---- dans le repertoire C:\Drivers\input ---- ---- dans le repertoire C:\Drivers\input\9FT4R ---- ---- dans le repertoire C:\Drivers\input\9FT4R\Bin ---- ---- dans le repertoire C:\Drivers\input\9FT4R\Bin\production ---- ---- dans le repertoire C:\Drivers\input\9FT4R\Bin\production\Windows10-x64 ---- fichier : HidEventFilter.cat fichier : HidEventFilter.inf fichier : HidEventFilter.sys ---- dans le repertoire C:\Drivers\network ---- ---- dans le repertoire C:\Drivers\network\6YDJP ---- ---- dans le repertoire C:\Drivers\network\6YDJP\Windows ---- ---- dans le repertoire C:\Drivers\network\6YDJP\Windows\WIN10 ---- ---- dans le repertoire C:\Drivers\network\6YDJP\Windows\WIN10\32 ---- fichier : rtux86w10.cat fichier : rtux86w10.INF fichier : rtux86w10.sys ---- dans le repertoire C:\Drivers\network\6YDJP\Windows\WIN10\64 ---- fichier : rtux64w10.cat fichier : rtux64w10.INF fichier : rtux64w10.sys ---- dans le repertoire C:\Drivers\storage ---- ---- dans le repertoire C:\Drivers\storage\1NN1D ---- ---- dans le repertoire C:\Drivers\storage\1NN1D\Drivers ---- ---- dans le repertoire C:\Drivers\storage\1NN1D\Drivers\Production ---- ---- dans le repertoire C:\Drivers\storage\1NN1D\Drivers\Production\Windows10-x64 ---- fichier : dpinst.exe fichier : HfcDisableService.exe fichier : iaAHCIC.cat fichier : iaAHCIC.inf fichier : iaStorAC.cat fichier : iaStorAC.inf fichier : iaStorAC.sys fichier : iaStorAfs.sys fichier : iaStorAfsNative.exe fichier : iaStorAfsService.exe fichier : iaStorSW.cat fichier : iaStorSW.inf fichier : iaStorSwExt.cat fichier : iaStorSwExt.inf fichier : Optane.dll fichier : RstMwService.exe fichier : ShellPackage.msi ---- dans le repertoire C:\Drivers\storage\M31NN ---- ---- dans le repertoire C:\Drivers\storage\M31NN\Drivers ---- ---- dans le repertoire C:\Drivers\storage\M31NN\Drivers\x64 ---- fichier : iaLPSS2_GPIO2.sys fichier : ialpss2_gpio2_cnl.cat fichier : iaLPSS2_GPIO2_CNL.inf fichier : iaLPSS2_I2C.sys fichier : ialpss2_i2c_cnl.cat fichier : iaLPSS2_I2C_CNL.inf fichier : iaLPSS2_SPI.sys fichier : ialpss2_spi_cnl.cat fichier : iaLPSS2_SPI_CNL.inf fichier : iaLPSS2_UART2.sys fichier : ialpss2_uart2_cnl.cat fichier : iaLPSS2_UART2_CNL.inf ---- dans le repertoire C:\Drivers\storage\R16KJ ---- ---- dans le repertoire C:\Drivers\storage\R16KJ\Install ---- ---- dans le repertoire C:\Drivers\storage\R16KJ\Install\DrvBin64 ---- ---- dans le repertoire C:\Drivers\storage\R16KJ\Install\DrvBin64\ExtInf ---- fichier : RtsCrExt.inf fichier : rtscrext64.cat fichier : SDRTCPRM.dll fichier : RsCRIcon.dll fichier : RtsPer.sys fichier : rtsper64.cat fichier : RtsperDLnQS.inf ---- dans le repertoire C:\Drivers\storage\TBT51 ---- ---- dans le repertoire C:\Drivers\storage\TBT51\production ---- ---- dans le repertoire C:\Drivers\storage\TBT51\production\Windows10-x64 ---- fichier : TbtBusDrv.sys fichier : TbtControlCenterToastLauncher.exe fichier : TbtFilterDrv.dll fichier : tbthostcontroller.cat fichier : TbtHostController.inf fichier : tbthostcontrollerextension.cat fichier : TbtHostControllerExtension.inf fichier : tbthostcontrollerhsacomponent.cat fichier : TbtHostControllerHsaComponent.inf fichier : tbtp2pndisdrv.cat fichier : TbtP2pNdisDrv.inf fichier : TbtP2pNdisDrv.sys fichier : ThunderboltService.exe
Dal
Cela fonctionne très bien, merci beaucoup. Il me reste tout de même un problème d'affichage à régler.
Je n'ai pas de console, uniquement une interface graphique ... Pour vérifier si cela fonctionnait, j'ai ajouté un "MessageBox" pour bien afficher tous les fichiers trouvés.
Cependant, l'objectif est de lister les dossiers et fichiers comme tu l'as montré.
J'ai ajouté ceci :
Cependant, lors de l’exécution, je n'ai pas tous les fichiers d'afficher, seulement quelques uns et le "dans le repertoire " n'est affiché qu'une seule fois ...
PS : je n'ai pas utilisé la fonction main(void), j'ai directement écris recursively_list_files(chemin); dans une boucle if dans mon main.c
Je n'ai pas de console, uniquement une interface graphique ... Pour vérifier si cela fonctionnait, j'ai ajouté un "MessageBox" pour bien afficher tous les fichiers trouvés.
Cependant, l'objectif est de lister les dossiers et fichiers comme tu l'as montré.
J'ai ajouté ceci :
... char path[MAX_PATH +1] FILE* fichier; fichier = fopen("donnees.txt", "w+"); sprintf(path, "%s\\*", dir); fprintf(fichier, "---- dans le repertoire %s ----\n\n", dir); if .... } else { /* c'est un fichier */ fprintf(fichier, "fichier : %s\n", fd.cFileName); .... fclose(fichier); }
Cependant, lors de l’exécution, je n'ai pas tous les fichiers d'afficher, seulement quelques uns et le "dans le repertoire " n'est affiché qu'une seule fois ...
PS : je n'ai pas utilisé la fonction main(void), j'ai directement écris recursively_list_files(chemin); dans une boucle if dans mon main.c
Comme la fonction est appelée récursivement, à chaque lancement de la fonction, tu crées un nouveau fichier donnees.txt qui écrase l'ancien (et qui fait d'autres choses horribles au retour de la fonction, car le pointeur sur FILE n'est pas le même).
Le plus simple dans ton cas est de faire :
dans la fonction qui appelle recursively_list_files() et de passer le pointeur sur FILE à cette fonction, dont le prototype serait alors
Ainsi, à chaque appel récursif de recursively_list_files() c'est le même pointeur sur FILE qui est passé et utilisé pour écrire dans le fichier ouvert en écriture.
Le
Le plus simple dans ton cas est de faire :
FILE * fichier; fichier = fopen("donnees.txt", "w+");
dans la fonction qui appelle recursively_list_files() et de passer le pointeur sur FILE à cette fonction, dont le prototype serait alors
void recursively_list_files(FILE * fichier, char * dir).
Ainsi, à chaque appel récursif de recursively_list_files() c'est le même pointeur sur FILE qui est passé et utilisé pour écrire dans le fichier ouvert en écriture.
Le
fclose(fichier);devrait aussi être dans la fonction qui appelle recursively_list_files() pour des raisons similaires.