Как извлечь имя файла из пути - PullRequest
32 голосов
/ 24 августа 2011

В Linux API / POSIX должно быть что-то элегантное для извлечения имени базового файла из полного пути

Ответы [ 10 ]

43 голосов
/ 24 августа 2011

См. char *basename(char *path).

Или выполните команду "man 3 basename" в целевой системе UNIX / POSIX.

13 голосов
/ 24 августа 2011

Используйте basename (который имеет нечетную угловую семантику) или сделайте это самостоятельно, вызвав strrchr(pathname, '/') и обработав всю строку как базовое имя, если она не содержит '/' символа.

4 голосов
/ 31 января 2017

Вот пример однострочного (задано char * whoami), который иллюстрирует основной алгоритм:

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

необходима дополнительная проверка, если NULL возможен. Также обратите внимание, что это просто указывает на исходную строку - "strdup()" может быть уместным.

1 голос
/ 19 июля 2018
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;
}

вызов: wchar_t * fileName = getFileNameFromPath (filePath);

1 голос
/ 13 января 2018

Функция basename() возвращает последний компонент пути, который может быть именем папки, а не именем файла. Существует две версии функции basename(): версия GNU и версия POSIX.

Версия GNU находится в string.h после включения #define _GNU_SOURCE:

    #define _GNU_SOURCE

    #include <string.h>

Версия GNU использует const и не изменяет аргумент.

    char * basename (const char *path)

Эта функция отменяется версией XPG (POSIX), если включено libgen.h.

    char * basename (char *path)

Эта функция может изменять аргумент, удаляя завершающие байты '/'. В этом случае результат может отличаться от версии GNU:

    basename("foo/bar/")

вернет строку «bar», если вы используете версию XPG, и пустую строку, если вы используете версию GNU.

Список литературы:

1 голос
/ 31 января 2017

Конечно, если это вопрос только для Gnu / Linux, вы можете использовать библиотечные функции.

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

И хотя некоторые могут не одобрить эти функции библиотеки Gnu, совместимые с POSIX, они не используют const. Как функции библиотеки полезности редко делают. Если это важно для вас, я думаю, вам придется придерживаться своей собственной функциональности, или, может быть, вам больше понравится?

#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;
}
1 голос
/ 05 октября 2013

Вы можете использовать strstr, если вас интересуют также имена каталогов:

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);
0 голосов
/ 18 сентября 2018

Вы можете использовать косую черту для обратной косой черты и использовать этот код:

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

}
0 голосов
/ 30 января 2017

@ Николай Хилюк предлагает лучшее решение, кроме.

1) Вернемся к использованию char *, абсолютно нет веских оснований для использования const.

2) Этот код не является переносимым и, вероятно, не будет работать ни в одной из систем POSIX, где /не является разделителем файловой системы в зависимости от реализации компилятора.Для некоторых компиляторов Windows вы можете захотеть проверить «\» вместо «/».Вы можете даже протестировать систему и установить разделитель на основе результатов.

Имя функции длинное, но описательное, проблем нет.Невозможно быть уверенным, что функция вернет имя файла, вы можете быть уверены, что это возможно, если функция закодирована правильно, чего вы добились.Хотя, если кто-то использует его в строке, которая не является путем, очевидно, он потерпит неудачу.Я бы, вероятно, назвал это basename, так как он сообщал бы многим программистам, какова его цель.Это всего лишь мое предпочтение, хотя, основываясь на моей предвзятости, твое имя в порядке.Насколько длина строки будет обрабатываться этой функцией и почему кто-то думал, что это будет точка?Вы вряд ли будете иметь дело с именем пути длиннее, чем то, что эта функция может обрабатывать в компиляторе ANSI C.Поскольку size_t определяется как длинное целое без знака, которое имеет диапазон от 0 до 4 294 967 295.

Я проверил вашу функцию следующим образом.

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

Отлично сработало, хотя Даниэль Камил Козар нашелошибка 1 off, которую я исправил выше.Ошибка будет отображаться только с неверно сформированным абсолютным путем, но, тем не менее, функция должна иметь возможность обрабатывать фиктивный ввод.Не слушайте всех, кто вас критикует.Некоторым людям просто нравится иметь мнение, даже когда оно ничего не стоит.

Мне не нравится решение strstr (), так как оно потерпит неудачу, если имя файла совпадает с именем каталога в пути, и даэто может происходить и происходит, особенно в системе POSIX, где исполняемые файлы часто не имеют расширения, по крайней мере, в первый раз, когда вам придется выполнять несколько тестов, а поиск разделителя с помощью strstr () становится еще более громоздким, посколькуспособ узнать, сколько разделителей может быть.Если вам интересно, почему человек хочет, чтобы базовое имя исполняемого файла Think busybox, egrep, fgrep и т. Д.

strrchar () было бы громоздким для реализации, так как он ищет символы, а не строки, поэтому яя не нахожу его почти таким же жизнеспособным или лаконичным, как это решение. Я исправлен Rad Lexus, это не было бы так громоздко, как я думал, так как strrchar () имеет побочный эффект от возвращения индекса строки за пределы найденного символа,

Береги себя

0 голосов
/ 22 января 2017

Мой пример:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...