12

I need to get parent directory from file in C++:

For example:

Input:

D:\Devs\Test\sprite.png

Output:

D:\Devs\Test\ [or D:\Devs\Test]

I can do this with a function:

char *str = "D:\\Devs\\Test\\sprite.png";
for(int i = strlen(str) - 1; i>0; --i)
{
    if( str[i] == '\\' )
    {
        str[i] = '\0';
        break;
    }
}

But, I just want to know there is exist a built-in function. I use VC++ 2003.

vietean
  • 2,975
  • 9
  • 40
  • 65

7 Answers7

20

If you're using std::string instead of a C-style char array, you can use string::find_last_of and string::substr in the following manner:

std::string str = "D:\\Devs\\Test\\sprite.png";
str = str.substr(0, str.find_last_of("/\\"));
user229044
  • 232,980
  • 40
  • 330
  • 338
Matt Kline
  • 10,149
  • 7
  • 50
  • 87
  • 2
    I like this answer, but I think it needs to address `string::npos` being returned if a directory separator isn't found. So if a directory separator is found, then what should be the parent directory path ends up being the file path. I think `string::npos` should be checked and `.` returned if a separator wasn't found. – tay10r Aug 25 '18 at 01:26
14

Now, with C++17 is possible to use std::filesystem::path::parent_path:

    #include <filesystem>
    namespace fs = std::filesystem;

    int main() {
        fs::path p = "D:\\Devs\\Test\\sprite.png";
        std::cout << "parent of " << p << " is " << p.parent_path() << std::endl;
        // parent of "D:\\Devs\\Test\\sprite.png" is "D:\\Devs\\Test"

        std::string as_string = p.parent_path().string();
        return 0;
    }
thakee nathees
  • 877
  • 1
  • 9
  • 16
4

Heavy duty and cross platform way would be to use boost::filesystem::parent_path(). But obviously this adds overhead you may not desire.

Alternatively you could make use of cstring's strrchr function something like this:

include <cstring>
char * lastSlash = strrchr( str, '\\');
if ( *lastSlash != '\n') *(lastSlash +1) = '\n';
J T
  • 4,946
  • 5
  • 28
  • 38
3

Editing a const string is undefined behavior, so declare something like below:

char str[] = "D:\\Devs\\Test\\sprite.png";

You can use below 1 liner to get your desired result:

*(strrchr(str, '\\') + 1) = 0; // put extra NULL check before if path can have 0 '\' also
Etienne de Martel
  • 34,692
  • 8
  • 91
  • 111
iammilind
  • 68,093
  • 33
  • 169
  • 336
3

On POSIX-compliant systems (*nix) there is a commonly available function for this dirname(3). On windows there is _splitpath.

The _splitpath function breaks a path into its four components.

void _splitpath(
   const char *path,
   char *drive,
   char *dir,
   char *fname,
   char *ext 
);

So the result (it's what I think you are looking for) would be in dir.

Here's an example:

int main()
{
    char *path = "c:\\that\\rainy\\day";
    char dir[256];
    char drive[8];
    errno_t rc;


    rc = _splitpath_s(
        path,       /* the path */
        drive,      /* drive */
        8,          /* drive buffer size */
        dir,        /* dir buffer */
        256,        /* dir buffer size */
        NULL,       /* filename */
        0,          /* filename size */
        NULL,       /* extension */
        0           /* extension size */
    );

    if (rc != 0) {
        cerr << GetLastError();
        exit (EXIT_FAILURE);
    }

    cout << drive << dir << endl;
    return EXIT_SUCCESS;
}
cnicutar
  • 178,505
  • 25
  • 365
  • 392
2

On Windows platforms, you can use PathRemoveFileSpec or PathCchRemoveFileSpec to achieve this. However for portability I'd go with the other approaches that are suggested here.

-3

You can use dirname to get the parent directory Check this link for more info

Raghu

Raghuram
  • 3,937
  • 2
  • 19
  • 25