如何从路径中提取文件名

时间:2011-08-24 18:17:28

标签: c

Linux API / POSIX中应该有一些优雅的东西可以从完整路径中提取基本文件名

10 个答案:

答案 0 :(得分:42)

请参阅char *basename(char *path)

或者在目标UNIX / POSIX系统上运行命令“man 3 basename”。

答案 1 :(得分:13)

使用basename(具有奇数边案例语义)或通过调用strrchr(pathname, '/')并将整个字符串视为基本名称(如果它不包含'/'字符)来自行完成。 / p>

答案 2 :(得分:4)

这是一个单行(给定char * whoami)的示例,它说明了基本算法:

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

如果可能为NULL,则需要进行额外检查。另请注意,这只是指向原始字符串 - " strdup()"可能是合适的。

答案 3 :(得分:1)

如果您对目录名称感兴趣,也可以使用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);

答案 4 :(得分:1)

当然,如果这只是一个Gnu / Linux问题,那么你可以使用库函数。

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

虽然有些人可能不赞成这些符合POSIX标准的Gnu库函数,但不使用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;
}

答案 5 :(得分:1)

basename()函数返回路径的最后一个组件,该组件可以是文件夹名称而不是文件名。 basename()函数有两个版本:GNU版本和POSIX版本。

包含string.h后,#define _GNU_SOURCE可以找到GNU版本:

    #define _GNU_SOURCE

    #include <string.h>

GNU版本使用const并且不修改参数。

    char * basename (const char *path)

如果包含libgen.h,则XPG(POSIX)版本会覆盖此功能。

    char * basename (char *path)

此函数可以通过删除尾随的'/'字节来修改参数。在这种情况下,结果可能与GNU版本不同:

    basename("foo/bar/")
如果您使用XPG版本,

将返回字符串“bar”,如果您使用GNU版本,则返回空字符串。

参考文献:

    basename(3) - Linux手册页
    Function: char * basename (const char *filename),在字符串中查找标记。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

您可以将斜杠转义为反斜杠并使用以下代码:

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

}

答案 8 :(得分:-3)

@Nikolay Khilyuk提供最佳解决方案,除了。

1)回到使用char *,没有充分的理由使用const。

2)此代码不可移植,并且可能在没有/不是文件系统分隔符的POSIX系统上失败,具体取决于编译器实现。对于某些Windows编译器,您可能希望测试&#39; \&#39;而不是&#39; /&#39;。您甚至可以测试系统并根据结果设置分隔符。

函数名称很长但是描述性,没有问题。无法确定函数是否会返回文件名,只有在函数编码正确的情况下才能确定它是否可以实现。虽然如果有人在不是路径的字符串上使用它,显然它会失败。我可能已经将它命名为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()解决方案,因为如果filename与路径中的目录名相同则会失败,是的,尤其是在可执行文件通常没有扩展名的POSIX系统上会发生这种情况,至少第一次意味着你必须做多次测试并用strstr()搜索分隔符更加麻烦,因为无法知道可能有多少分隔符。如果你想知道为什么一个人想要一个可执行文件的基本名称认为busybox,egrep,fgrep等......

strrchar()实现起来很麻烦,因为它搜索字符而不是字符串,所以我发现它几乎不像这个解决方案那么可行或简洁。我认为Rad雷克斯不会这样做因为我认为strrchar()具有将字符串的索引返回到找到的字符之外的副作用。

保重

答案 9 :(得分:-4)

我的例子:

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