C语言 如何从路径中提取文件名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7180293/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:28:13  来源:igfitidea点击:

How to extract filename from path

c

提问by pic11

There should be something elegant in Linux API/POSIX to extract base file name from full path

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

回答by maerics

See char *basename(char *path).

char *basename(char *path)

Or run the command "man 3 basename" on your target UNIX/POSIX system.

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

回答by R.. GitHub STOP HELPING ICE

Use basename(which has odd corner case semantics) or do it yourself by calling strrchr(pathname, '/')and treating the whole string as a basename if it does not contain a '/'character.

使用basename(它具有奇怪的极端情况语义)或通过调用strrchr(pathname, '/')整个字符串并将其视为基本名称(如果它不包含'/'字符)来自己完成。

回答by John Hascall

Here's an example of a one-liner (given char * whoami) which illustrates the basic algorithm:

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

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

an additional check is needed if NULL is a possibility. Also note that this just points into the original string -- a "strdup()" may be appropriate.

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

回答by Diego

The basename()function returns the last component of a path, which could be a folder name and not a file name. There are two versions of the basename()function: the GNU version and the POSIX version.

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

The GNU version can be found in string.hafter you include #define _GNU_SOURCE:

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

    #define _GNU_SOURCE

    #include <string.h>

The GNU version uses constand does not modify the argument.

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

    char * basename (const char *path)

This function is overridden by the XPG (POSIX) version if libgen.his included.

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

    char * basename (char *path)

This function may modify the argument by removing trailing '/' bytes. The result may be different from the GNU version in this case:

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

    basename("foo/bar/")

will return the string "bar" if you use the XPG version and an empty string if you use the GNU version.

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

References:

参考:

    basename (3) - Linux Man Pages
    basename (3) - Linux 手册页
    Function: char * basename (const char *filename), Finding Tokens in a String.
    功能: char * basename (const char *filename),在字符串中查找标记。

回答by Teo

template<typename chatType>
chatType* getFileNameFromPath( chatType* path )
{
    if( path == NULL )
        return NULL;

    chatType * pFileName = path;
    for( chatType * pCur = path; *pCur != '
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);
'; pCur++) { if( *pCur == '/' || *pCur == '\' ) pFileName = pCur+1; } return pFileName; }

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

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

回答by Amir

You could use strstrin case you are interested in the directory names too:

strstr如果您也对目录名称感兴趣,则可以使用:

#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)] = '
#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;

}
'; (fn = strrchr(input, '/')) ? ++fn : (fn = input); printf("%s\n", fn); return 0; }

回答by Jamie R Robillard Sr.

Of course if this is a Gnu/Linux only question then you could use the library functions.

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

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

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

And though some may disapprove these POSIX compliant Gnu Library functions do not use const. As library utility functions rarely do. If that is important to you I guess you will have to stick to your own functionality or maybe the following will be more to your taste?

尽管有些人可能不赞成这些符合 POSIX 标准的 Gnu 库函数不使用 const。库实用程序函数很少这样做。如果这对您很重要,我想您将不得不坚持自己的功能,或者以下内容更符合您的口味?

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

回答by AnonymousUser

You can escape slashes to backslash and use this code:

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

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

回答by Jamie R Robillard Sr.

@Nikolay Khilyuk offers the best solution except.

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

1) Go back to using char *, there is absolutely no good reason for using const.

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

2) This code is not portable and is likely to fail on none POSIX systems where the / is not the file system delimiter depending on the compiler implementation. For some windows compilers you might want to test for '\' instead of '/'. You might even test for the system and set the delimiter based on the results.

2) 此代码不可移植,并且可能在非 POSIX 系统上失败,其中 / 不是文件系统定界符,具体取决于编译器实现。对于某些 Windows 编译器,您可能想要测试 '\' 而不是 '/'。您甚至可以测试系统并根据结果设置分隔符。

The function name is long but descriptive, no problem there. There is no way to ever be sure that a function will return a filename, you can only be sure that it can if the function is coded correctly, which you achieved. Though if someone uses it on a string that is not a path obviously it will fail. I would have probably named it basename, as it would convey to many programmers what its purpose was. That is just my preference though based on my bias your name is fine. As far as the length of the string this function will handle and why anyone thought that would be a point? You will unlikely deal with a path name longer than what this function can handle on an ANSI C compiler. As size_t is defined as a unsigned long int which has a range of 0 to 4,294,967,295.

函数名称很长但具有描述性,没有问题。没有办法确定一个函数会返回一个文件名,你只能确定它可以,如果函数编码正确,你实现了。尽管如果有人在不是路径的字符串上使用它,显然它会失败。我可能会将它命名为 basename,因为它会向许多程序员传达它的用途。这只是我的偏好,但基于我的偏见,你的名字很好。至于这个函数将处理的字符串的长度,为什么有人认为这很重要?您不太可能处理比此函数在 ANSI C 编译器上可以处理的路径名更长的路径名。因为 size_t 被定义为一个 unsigned long int,其范围为 0 到 4,294,967,295。

I proofed your function with the following.

我用以下内容证明了您的功能。

##代码##

Worked great, though Daniel Kamil Kozar did find a 1 off error that I corrected above. The error would only show with a malformed absolute path but still the function should be able to handle bogus input. Do not listen to everyone that critiques you. Some people just like to have an opinion, even when it is not worth anything.

效果很好,尽管 Daniel Kamil Kozar 确实发现了我在上面更正的 1 off 错误。该错误只会显示格式错误的绝对路径,但该函数仍然应该能够处理虚假输入。不要听每个批评你的人。有些人只是喜欢发表意见,即使它一文不值。

I do not like the strstr() solution as it will fail if filename is the same as a directory name in the path and yes that can and does happen especially on a POSIX system where executable files often do not have an extension, at least the first time which will mean you have to do multiple tests and searching the delimiter with strstr() is even more cumbersome as there is no way of knowing how many delimiters there might be. If you are wondering why a person would want the basename of an executable think busybox, egrep, fgrep etc...

我不喜欢 strstr() 解决方案,因为如果文件名与路径中的目录名相同,它就会失败,是的,这可能并且确实发生,尤其是在可执行文件通常没有扩展名的 POSIX 系统上,至少第一次意味着您必须进行多次测试,并且使用 strstr() 搜索分隔符更加麻烦,因为无法知道可能有多少个分隔符。如果你想知道为什么一个人想要一个可执行文件的基名,想想 busybox、egrep、fgrep 等等......

strrchar() would be cumbersome to implement as it searches for characters not strings so I do not find it nearly as viable or succinct as this solution.I stand corrected by Rad Lexus this would not be as cumbersome as I thought as strrchar() has the side effect of returning the index of the string beyond the character found.

strrchar() 实现起来会很麻烦,因为它搜索的是字符而不是字符串,所以我认为它不像这个解决方案那样可行或简洁。我接受 Rad Lexus 的纠正,这不会像我想象的那么麻烦,因为 strrchar() 具有返回超出找到的字符的字符串索引的副作用。

Take Care

小心

回答by Nikolay Khilyuk

My example:

我的例子:

##代码##