【问题标题】:Parse out the file extension from a file-path in C从 C 中的文件路径解析文件扩展名
【发布时间】:2009-11-10 20:51:25
【问题描述】:

我之前使用以下代码来确定文件是 .exe 还是 .o 文件,因此将 binFile 设置为 1:

if(strstr(fpath,".exe") != NULL || strstr(fpath,".o") != NULL)
          binFile = 1;

通过调试,我注意到此方法还会将 binFile 设置为 1,其中包含 foo.out 或 foo.execute 之类的文件。我真正想要的是匹配 '.exe\0' 和 '.o\0' 但 strstr() 说它忽略了终止的 NUL 字节。我该怎么办?

谢谢

【问题讨论】:

    标签: c file string


    【解决方案1】:
    #include <stdio.h>
    #include <string.h>
    
    int endswith(const char* haystack, const char* needle)
    {
        size_t hlen;
        size_t nlen;
        /* find the length of both arguments - 
        if needle is longer than haystack, haystack can't end with needle */
        hlen = strlen(haystack); 
        nlen = strlen(needle);
        if(nlen > hlen) return 0;
    
        /* see if the end of haystack equals needle */
        return (strcmp(&haystack[hlen-nlen], needle)) == 0;
    }
    
    int main(int argc, char** argv) {
    
        if(argc != 3) {
            printf("Usage: %s <string> <test-ending>\n", argv[0]);
            return 1;
        }
    
        printf("Does \"%s\" end with \"%s\"? ", argv[1], argv[2]);
    
        if(endswith(argv[1], argv[2])) {
            printf("Yes!\n");
        } else {
            printf("No!\n");
        }
    
        return 0;
    }
    

    【讨论】:

    • 感谢好评的节目
    • 字符串长度最好使用size_t 而不是int
    【解决方案2】:
    char *ext = strrchr(fpath, '.');
    
    if (ext && (!strcmp(ext, ".exe") || !strcmp(ext, ".o")))
       binfile = 1;
    

    如果您的系统有 BSD/POSIX strcasecmp,您可能应该使用它而不是 strcmp

    【讨论】:

    • 我一直不明白为什么 case-insensitive 版本的名称中有 case。在我看来,这似乎倒退了。我希望不只是我。
    【解决方案3】:
    int iLen = strlen(fpath);
    if  ((iLen >= 4 && strcmp(&fpath[iLen - 4], ".exe") == 0)
      || (iLen >= 2 && strcmp(&fpath[iLen - 2], ".o") == 0))
       binfile = 1;
    

    编辑添加了长度测试,以处理非常短的文件名。

    【讨论】:

    • 您可能需要检查并确保 fpath 的长度分别大于 4 或 2。在 iLen 为 3 之前,iLen -4 非常好。:)
    • 我已经在我的回答中概括了这种方法 - 没有不安全的索引。
    • @Joe,对了,感谢您指出这一点!我会相应地进行编辑。
    • 另外,您错过了 if 语句周围的括号。但是感谢您的有效回答。
    • @SiegeX,对,我也忘了。最近做的 Python 太多了,我很幸运 ;-)
    【解决方案4】:

    您可以检查 strstr 的结果(考虑到搜索字符串的长度)以查看它是否为 NULL。示例:

    const char* p = strstr(fpath,".exe");
    
    if (p != NULL && *(p + 4 + 1) == 0) // 4 is the length of ".exe"; +1 should get you to \0
        binFile = 1;
    

    【讨论】:

    • 您的代码没有为名为“foo.exe.exe”的文件做正确的事情
    【解决方案5】:

    我喜欢得到扩展然后检查它。

    char *suffix = strrchr(fpath,'.');
    
    if (suffix)
    {
      suffix++;
      if (!strcasecmp(suffix,"exe"))
      {
        // you got it
      }
    }
    

    增加后缀是可以的,因为你知道它指向那个时候找到的一个时期。增加它最坏的情况是使它指向空终止字符,这根本不会打扰 strcasecmp。

    您也可以通过这种方式轻松检查扩展列表。

    【讨论】:

    • +1 用于使用 strrchr()... 所有这些其他答案都在重新发明它,使用太多代码。 (PS:你想要 strrchr() 的单引号,而不是双引号..)
    • asveikau 是对的,我将双引号固定为单引号。我想我太依赖编译器来捕捉我的错别字了。
    • 注意“文件”中的空后缀。
    • 空后缀没问题,在我的代码后面的第一句就解决了。 “增加它最坏的情况是让它指向空终止字符,这根本不会打扰 strcasecmp。” strcasecmp 只会返回不匹配的 exe。
    【解决方案6】:

    一种方法:

    char * suffix = fpath;
    char * i = fpath;
    while (*i++) {
        if (*i == '.') {
            suffix = i;
        }
    }
    
    if (!strcmp(suffix, ".o") || !strcmp(suffix, ".exe")) {
        /* do stuff */
    }
    

    【讨论】:

    • 如果您的文件路径包含更多的 . 而不仅仅是文件扩展名,这将失败:即:“d:\hello.there\somefile.o” 您应该从右到左搜索期间。
    • @KSchmidt:不,不会。请注意即使在找到一个点之后 while 循环如何继续,因此确保后缀将指向最后一次遇到。
    • 我现在明白了,但为什么不直接使用 strrchr?
    • strrchr 将是首选方式,我只是一个小时前还不熟悉它。
    【解决方案7】:

    您也可以使用_splitpath/_wsplitpath,它是 CRT 的一部分。

    http://msdn.microsoft.com/en-us/library/e737s6tf(v=vs.80).aspx

    【讨论】:

      猜你喜欢
      • 2011-12-08
      • 1970-01-01
      • 1970-01-01
      • 2012-10-11
      • 2019-04-22
      • 2012-10-06
      • 1970-01-01
      • 2022-06-23
      相关资源
      最近更新 更多