Comment extraire le nom de fichier du chemin

Il devrait y avoir quelque chose d’élégant dans Linux API / POSIX pour extraire le nom de fichier de base du chemin complet. Je vous remercie.

Voir char *basename(char *path) .

Ou exécutez la commande ” man 3 basename ” sur votre système UNIX / POSIX cible.

Utilisez basename (qui a une sémantique de cas impair) ou faites-le vous-même en appelant strrchr(pathname, '/') et en traitant la chaîne entière comme un nom de base si elle ne contient pas de caractère '/' .

Voici un exemple d’une ligne ( char * whoami ) qui illustre l’algorithme de base:

 (whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]); 

une vérification supplémentaire est nécessaire si NULL est une possibilité. Notez également que cela pointe juste dans la chaîne d’origine – un ” strdup() ” peut être approprié.

Vous pouvez aussi utiliser strstr si les noms de répertoires vous intéressent également:

 char *path ="ab/cde/fg.out"; char *ssc; int l = 0; ssc = strstr(path, "/"); do{ l = strlen(ssc) + 1; path = &path[strlen(path)-l+2]; ssc = strstr(path, "/"); }while(ssc); printf("%s\n", path); 

Bien sûr, s’il s’agit d’une question réservée à Gnu / Linux, vous pouvez utiliser les fonctions de la bibliothèque.

https://linux.die.net/man/3/basename

Et même si certains désapprouvent ces fonctions de la bibliothèque Gnu compatibles POSIX, n’utilisez pas const. Comme l’utilitaire de bibliothèque fonctionne rarement. Si cela est important pour vous, je suppose que vous devrez vous en tenir à votre propre fonctionnalité ou peut-être que ce qui suit sera plus à votre goût?

 #include  #include  int main(int argc, char *argv[]) { char *fn; char *input; if (argc > 1) input = argv[1]; else input = argv[0]; /* handle trailing '/' eg input == "/home/me/myprogram/" */ if (input[(strlen(input) - 1)] == '/') input[(strlen(input) - 1)] = '\0'; (fn = strrchr(input, '/')) ? ++fn : (fn = input); printf("%s\n", fn); return 0; } 

La fonction basename() renvoie le dernier composant d’un chemin, qui pourrait être un nom de dossier et non un nom de fichier. Il existe deux versions de la fonction basename() : la version GNU et la version POSIX.

La version GNU est disponible dans ssortingng.h après l’inclusion de #define _GNU_SOURCE :

     #define _GNU_SOURCE

     #include 

La version GNU utilise const et ne modifie pas l’argument.

  char * basename (const char * path) 

Cette fonction est remplacée par la version XPG (POSIX) si libgen.h est inclus.

  char * basename (char * path) 

Cette fonction peut modifier l’argument en supprimant les octets de fin. Le résultat peut être différent de la version GNU dans ce cas:

  nom de base ("foo / bar /") 

retournera la chaîne “bar” si vous utilisez la version XPG et une chaîne vide si vous utilisez la version GNU.

Références:

    nom de base (3) – Linux Man Pages
    Fonction: char * basename (const char * nomfichier) , Recherche de jetons dans une chaîne.

 template chatType* getFileNameFromPath( chatType* path ) { if( path == NULL ) return NULL; chatType * pFileName = path; for( chatType * pCur = path; *pCur != '\0'; pCur++) { if( *pCur == '/' || *pCur == '\\' ) pFileName = pCur+1; } return pFileName; } 

appelez: wchar_t * fileName = getFileNameFromPath (filePath);

Je ne veux pas être tatillon ici sur ce que les autres postent mais …

  1. L’appel de certaines fonctions “maison” suggérées (telles que: getFileNameFromPath("") ) plantera le programme.
  2. Je recommanderais certaines précautions lors de la désignation de fonctions qui prétendent de manière inhérente que le résultat sera un fichier. getFilenameFromPath("/usr/local") retournera "local" (sans les guillemets) bien que sur un système de fichiers Unix, il s’agisse généralement d’un dossier.

Vous pouvez échapper aux barres obliques inverses pour utiliser le code suivant:

 #include  #include  int main(void) { char path[] = "C:\\etc\\passwd.c"; //ssortingng with escaped slashes char temp[256]; //result here char *ch; //define this ch = strtok(path, "\\"); //first split while (ch != NULL) { strcpy(temp, ch);//copy result printf("%s\n", ch); ch = strtok(NULL, "\\");//next split } printf("last filename: %s", temp);//result filename return 0; } 

Mon exemple:

 const char* getFileNameFromPath(const char* path) { for(size_t i = strlen(path) - 1; i >= 0; i--) { if (path[i] == '/') { return &path[i+1]; } } return path; } 

@ Nikolay Khilyuk offre la meilleure solution sauf.

1) Revenez à l’utilisation de char *, il n’y a absolument aucune bonne raison d’utiliser const.

2) Ce code n’est pas portable et risque d’échouer sur les systèmes POSIX où le / n’est pas le délimiteur de système de fichiers dépendant de l’implémentation du compilateur. Pour certains compilateurs Windows, vous pouvez tester “\” au lieu de “/”. Vous pouvez même tester le système et définir le délimiteur en fonction des résultats.

Le nom de la fonction est long mais descriptif, pas de problème. Il n’y a aucun moyen de jamais être sûr qu’une fonction retournera un nom de fichier, vous pouvez seulement en être sûr si la fonction est correctement codée, ce que vous avez réalisé. Cependant, si quelqu’un l’utilise sur une chaîne qui n’est pas un chemin, il échouera évidemment. J’aurais probablement nommé ce nom de base, car il indiquerait à de nombreux programmeurs quelle était sa fonction. Ce n’est que ma préférence, bien que mon prénom soit bien fondé sur mon parti pris. En ce qui concerne la longueur de la chaîne que cette fonction va gérer et pourquoi quelqu’un pense que ce serait un point? Il est peu probable que vous traitiez avec un nom de chemin plus long que ce que cette fonction peut gérer sur un compilateur ANSI C. Comme size_t est défini comme un unsigned long int qui a une plage de 0 à 4 294 967 295.

J’ai vérifié votre fonction avec ce qui suit.

  #include  #include  char* getFileNameFromPath(char* path); int main(int argc, char *argv[]) { char *fn; fn = getFileNameFromPath(argv[0]); printf("%s\n", fn); return 0; } char* getFileNameFromPath(char* path) { for(size_t i = strlen(path) - 1; i; i--) { if (path[i] == '/') { return &path[i+1]; } } return path; } 

A bien fonctionné, mais Daniel Kamil Kozar a trouvé une erreur que j’ai corrigée ci-dessus. L’erreur ne s’afficherait qu’avec un chemin absolu mal formé, mais la fonction devrait néanmoins être capable de gérer une entrée fausse. N’écoutez pas tous ceux qui vous critiquent. Certaines personnes aiment juste avoir une opinion, même si cela ne vaut rien.

Je n’aime pas la solution strstr () car elle échouera si le nom du fichier est identique à un nom de répertoire dans le chemin. Oui, cela peut arriver et se produit surtout sur un système POSIX où les fichiers exécutables n’ont souvent pas d’extension, du moins le Pour la première fois, vous devrez faire plusieurs tests et rechercher le délimiteur avec strstr () est encore plus fastidieux, car il n’ya aucun moyen de savoir combien de délimiteurs il pourrait y avoir. Si vous vous demandez pourquoi une personne voudrait avoir le nom de base d’un exécutable, pensez à busybox, par exemple, egrep, fgrep, etc.

strrchar () serait compliqué à mettre en œuvre car il recherche des caractères et non des chaînes, donc je ne le trouve pas aussi viable et succinct que cette solution. Je suis corrigé par Rad Lexus, cela ne serait pas aussi lourd que je pensais car strrchar () avait pour effet secondaire de renvoyer l’index de la chaîne au-delà du caractère trouvé.

Prends soin