c - purposes - hashtag instagram per youtube



Come estrarre il nome del file dal percorso (8)

Ci dovrebbe essere qualcosa di elegante in Linux API / POSIX per estrarre il nome del file di base dal percorso completo. Grazie.


Answer #1

@ Nikolay Khilyuk offre la migliore soluzione tranne.

1) Torna a usare char *, non c'è assolutamente nessuna buona ragione per usare const.

2) Questo codice non è portatile ed è probabile che fallisca su nessuno dei sistemi POSIX in cui il / non è il delimitatore del file system a seconda dell'implementazione del compilatore. Per alcuni compilatori Windows potresti voler testare '\' invece di '/'. Potresti anche testare il sistema e impostare il delimitatore in base ai risultati.

Il nome della funzione è lungo ma descrittivo, nessun problema. Non c'è modo di essere sicuri che una funzione restituisca un nome di file, puoi solo essere sicuro che lo può se la funzione è codificata correttamente, cosa che hai ottenuto. Anche se qualcuno lo usa su una stringa che non è un percorso ovviamente fallirà. Probabilmente l'avrei chiamato basename, in quanto avrebbe trasmesso a molti programmatori quale fosse il suo scopo. Questa è solo la mia preferenza, ma in base al mio pregiudizio il tuo nome va bene. Per quanto riguarda la lunghezza della stringa che questa funzione gestirà e perché qualcuno ha pensato che sarebbe stato un punto? Improbabilmente gestirai un nome di percorso più lungo di quello che questa funzione può gestire su un compilatore ANSI C. Poiché size_t è definito come int lungo non firmato che ha un intervallo compreso tra 0 e 4.294.967.295.

Ho provato la tua funzione con quanto segue.

    #include <stdio.h>
    #include <string.h>

    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;
    }

Ha funzionato benissimo, anche se Daniel Kamil Kozar ha trovato un errore 1 che ho corretto sopra. L'errore verrebbe visualizzato solo con un percorso assoluto non valido, ma la funzione dovrebbe comunque essere in grado di gestire l'input falso. Non ascoltare tutti quelli che ti criticano. Ad alcune persone piace avere un'opinione, anche quando non vale niente.

Non mi piace la soluzione strstr () in quanto fallirà se il nome del file è lo stesso di un nome di directory nel percorso e sì che può e si verifica soprattutto su un sistema POSIX dove i file eseguibili spesso non hanno un'estensione, almeno il la prima volta che vorrà dire che devi fare più test e cercare il delimitatore con strstr () è ancora più ingombrante in quanto non c'è modo di sapere quanti delimitatori potrebbero esserci. Se ti stai chiedendo perché una persona vorrebbe che il nome di base di un eseguibile pensi busybox, egrep, fgrep ecc ...

strrchar () sarebbe ingombrante da implementare mentre cerca caratteri non stringhe quindi non trovo quasi fattibile o succinta come questa soluzione. Resto corretto da Rad Lexus, non sarebbe così complicato come pensavo che strrchar () abbia l'effetto collaterale di restituire l'indice della stringa oltre il carattere trovato.

Stai attento


Answer #2

Ecco un esempio di one-liner (dato char * whoami ) che illustra l'algoritmo di base:

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

è necessario un ulteriore controllo se NULL è una possibilità. Nota anche che questo punta solo nella stringa originale - un " strdup() " potrebbe essere appropriato.


Answer #3

La funzione basename() restituisce l'ultimo componente di un percorso, che potrebbe essere un nome di cartella e non un nome di file. Esistono due versioni della funzione basename() : la versione GNU e la versione POSIX.

La versione GNU può essere trovata in string.h dopo aver incluso #define _GNU_SOURCE :

    #define _GNU_SOURCE

    #include <string.h>

La versione GNU utilizza const e non modifica l'argomento.

    char * basename (const char *path)

Questa funzione è sovrascritta dalla versione XPG (POSIX) se è incluso libgen.h .

    char * basename (char *path)

Questa funzione può modificare l'argomento rimuovendo i '/' byte finali. In questo caso il risultato potrebbe essere diverso dalla versione GNU:

    basename("foo/bar/")

restituirà la stringa "bar" se si utilizza la versione XPG e una stringa vuota se si utilizza la versione GNU.

Riferimenti:

    basename (3) - Linux Man Pages
    Funzione: char * basename (const char * nomefile) , Ricerca di token in una stringa.


Answer #4

Naturalmente se questa è una domanda solo su Gnu / Linux, allora potresti usare le funzioni della libreria.

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

E sebbene alcuni possano disapprovare queste funzioni Gnu Library compatibili con POSIX, non utilizzare const. Come funzioni di utilità di libreria raramente. Se questo è importante per te, immagino che dovrai rispettare le tue stesse funzionalità o forse quanto segue sarà più adatto ai tuoi gusti?

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *fn;
    char *input;

    if (argc > 1)
        input = argv[1];
    else
        input = argv[0];

    /* handle trailing '/' e.g. 
       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;
}

Answer #5

Puoi sfuggire alle barre inverse e utilizzare questo codice:

#include <stdio.h>
#include <string.h>

int main(void)
{
  char path[] = "C:\\etc\\passwd.c"; //string 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;

}

Answer #6

Puoi usare strstr nel caso tu sia interessato anche ai nomi delle directory:

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);

Answer #7

Vedi char *basename(char *path) .

Oppure esegui il comando " man 3 basename " sul tuo sistema UNIX / POSIX di destinazione.


Answer #8
template<typename chatType>
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;
}

call: wchar_t * fileName = getFileNameFromPath <wchar_t> (filePath);





c