如何在C语言中从完整路径获取文件所在目录

8
我正在尝试从传入的文件名(例如C:\some\dir\file)动态获取父目录(假设是C:\some\dir),并将其放入char*中。我已经有了完整的路径和文件名char*。如何在C语言中实现这一点?
我有一些代码,但我的思维混乱,我无法理解它。我该如何重构/重写它?
/* Gets parent directory of file being compiled */
    short SlashesAmount;
    short NamePosition;
    short NameLength;
    char* Pieces[SlashesAmount];
    char* SplitPath;
    short ByteNumber;
    short PieceNumber;
    char* ScriptDir;
    NameLength = strlen(File);

    //Dirty work
    SplitPath = strtok(File, "\");
    do {
        ByteNumber = 0;
        do {
            File[NamePosition] = CurrentPiece[ByteNumber];
            NamePosition++;
        } while(File[NamePosition] != '\n');
        PieceNumber++;
    } while(NamePosition < NameLength);

2
使用char *strrchr(const char *string, int c);strrchr(File, '\\') = '\0';,注意strtok()会修改第一个参数。 - Grijesh Chauhan
5个回答

14
你需要的是 dirname(3),这只在 POSIX 系统上可用。
Windows 的替代方案是 _splitpath_s
errno_t _splitpath_s(
   const char * path,
   char * drive,
   size_t driveNumberOfElements,
   char * dir,
   size_t dirNumberOfElements,
   char * fname,
   size_t nameNumberOfElements,
   char * ext, 
   size_t extNumberOfElements
);

示例代码(未经测试):

#include <stdlib.h>
const char* path = "C:\\some\\dir\\file";
char dir[256];

_splitpath_s(path,
    NULL, 0,             // Don't need drive
    dir, sizeof(dir),    // Just the directory
    NULL, 0,             // Don't need filename
    NULL, 0);           

这难道不是特定于Linux吗? - Digital_Reality
哦,我的天啊,非常感谢您。你救了我一个噩梦。 - AlexTheRose
1
注意:_splitpath_s 不会返回带有 dir 的驱动器。因此,上面的示例只会返回 \\some\\dir,而不是 C:\\some\\dir。因此,如果您正在处理可能不在 C 驱动器上的文件,则必须使用 _splitpath_s 获取驱动器和目录,然后使用 _makepath_s 将它们组合起来。 - Nik

6

您已经有了文件的完整路径(例如:C:\some\dir\file.txt),只需执行以下操作:
1. 使用strrchr()函数找到最后一个斜杠,将其命名为p
2. 从路径的开头复制到p - 1(不包括'/')
因此,代码应如下所示:

char *lastSlash = NULL;
char *parent = NULL;
lastSlash = strrchr(File, '\\'); // you need escape character
parent = strndup(File, strlen(File) - (lastSlash - 1));

0
int len = strlen(filepath);  
char* dir = malloc(len + 1);
strcpy(dir, filepath);
while (len > 0) {
   len--;
   if (dir[len] == '\\' || dir[len] == '/') {
      dir[len] = '\0';
      break;
   }
}

2
无论您的代码是否正常工作,如果您没有使用malloc释放已分配的内存,那么这是一种不好的做法。内存泄漏是不好的。 - SolverWorld
1
虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。您可以在帮助中心找到有关编写良好答案的更多信息:https://stackoverflow.com/help/how-to-answer。祝你好运! - nima

0

没有足够的声望来评论,所以在这里添加一个答案。

正如Grijesh Chauhan在问题中评论的那样,您可以使用strrchr()来获取原始字符串的较短版本。

然而,strrchr()的返回值是char *,不应该被赋值为\0,这会使它指向空,相反,您可以使用*[0]来修改它的第一个元素以缩短原始字符串。

像这样:

strrchr(File, '\\')[0] = '\0'

// or this
*(strrchr(File, '\\') = '\0'

非常好的回答,Grijesh应该把它作为答案:D


-1
这里有一个函数,它获取完整路径和缓冲区。 它将更新缓冲区到父路径。 该函数已经过检查。享受 :)
/*
Use: Get parent path by full path
Input: full path, parent buffer
Output: None
*/
void getParent(char* path, char* parent)
{
    int parentLen;
    char* last = strrchr(path, '/');

    if (last != NULL) {

        parentLen = strlen(path) - strlen(last + 1);
        strncpy(parent, path, parentLen);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接