Как извлечь имя файла из пути

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

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

Вы можете использовать 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);

Ответ 5

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

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

И хотя некоторые могут отклонить эти функции Gnu Library, совместимые с 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;
}

Ответ 6

Функция 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. basename (3) - Личные страницы Linux
Функция: char * basename (const char * filename), Поиск токенов в строке.

Ответ 7

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 <wchar_t> (filePath);

Ответ 8

Я не хочу быть ничем, собирающим здесь то, что другие люди публикуют, но...

  1. Вызов некоторых предложенных "домашних" функций (таких как: getFileNameFromPath("")) приведет к сбою программы.
  2. Я бы порекомендовал некоторую осторожность при именовании функций, которые по своей природе утверждают, что результатом будет файл. getFilenameFromPath("/usr/local") вернет "local" (без кавычек), хотя в файловой системе unix обычно бывает, что это папка.

Ответ 9

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

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

}

Ответ 10

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

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

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

Имя функции длинное, но описательное, без проблем. Невозможно никогда не быть уверенным, что функция вернет имя файла, вы можете быть уверены только в том, что это возможно, если функция закодирована правильно, чего вы достигли. Хотя, если кто-то использует его на строке, которая не является курсом, очевидно, что это не сработает. Вероятно, я бы назвал это basename, поскольку он передал бы многим программистам, какова была его цель. Это только мое предпочтение, хотя на основе моего предвзятости ваше имя прекрасное. Что касается длины строки, с которой эта функция будет работать, и почему кто-то думал, что это будет точка? Вы вряд ли будете иметь дело с именем пути дольше, чем эта функция может обрабатывать на компиляторе ANSI C. Поскольку size_t определяется как unsigned long int, который имеет диапазон от 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, которую я исправил выше. Ошибка будет отображаться только с искаженным абсолютным путем, но все же функция должна иметь возможность обрабатывать фиктивные входные данные. Не слушайте всех, кто критикует вас. Некоторым людям просто нравится иметь мнение, даже если это ничего не стоит.

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

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

Береги себя

Ответ 11

Мой пример:

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