c++ - Splitting an absolute file path
Asked Answered
H

7

3

I'm writing a C++ program for a school assignment. At some point, the question requires me to change directories, which I know how to do. However, the user will provide the program with the absolute path of a file. What I'm trying to do is to change the directory to where that file is. For example, if I'm in a directory dir2, and the user want to go to the file

     /home/dir1/dir2/dir3/dir4/file

I would like to do

     int ret = chdir("home/dir1/dir2/dir3/dir4");

My question is how can I split the user-given string into

     /home/dir1/dir2/dir3/dir4/

and

     file

EDITI figured it out. I first converted the absolute pathname from a const char* to a string. Then I used the .find_last_of("/") string member to find the position of the last "/" in the string. Then I used the .substr() member to get the substring from 0 to that position returned by .find_last_of

Hexa answered 20/2, 2016 at 22:51 Comment(3)
Place your rubber duck -- en.wikipedia.org/wiki/Rubber_duck_debugging -- next to your keyboard, and explain to your rubber duck, in plain English, your logical, step by step, algorithm that does this. Once your rubber duck agrees that your algorithm will work, simply take your explanation, and translate it into code.Nikolas
I'm not quite sure what options I have to split strings this way.. I know that I can split it based on whitespace using stringstreams. But this is a different delimiter. I'd like to split it according to the last '/'Hexa
The std::string class has methods to split, and chop up the string, in any way that pleases you. If you want to extract parts of the string before or after position #n, std::string offers several methods to do so.Nikolas
B
10

Every other answer to this question finds "/" (Unix) or "\" (Windows), and chops up the string manually; this is verbose and subject to user error. C++17 now has the std::filesystem package, which cleanly extracts directory and filename from a path in an OS friendly manner:

#include <filesystem>

void Test()
{
    std::filesystem::path path("/home/dir1/dir2/dir3/dir4/file");
    std::string dir = path.parent_path().string(); // "/home/dir1/dir2/dir3/dir4"
    std::string file = path.filename().string(); // "file"
}
Bogoch answered 16/11, 2021 at 14:28 Comment(0)
C
6

Put your path into an std::string and then you can do something like the below.

std::string path = "/home/person/dir/file";
std::size_t botDirPos = path.find_last_of("/");
// get directory
std::string dir = path.substr(0, botDirPos);
// get file
std::string file = path.substr(botDirPos, path.length());
// change directory.
chdir(dir.c_str());
Cedell answered 20/2, 2016 at 23:7 Comment(0)
T
4

Simply get the last index of the "/" character in the file path, and snip the file with it's extension from the string.

1) Check that the directory listing has a "/". If not - throw an error.

2) Get the last index of the "/" in the string.

3) Return a sub string of the directory string, using the last index of function result (a number) as your starting index and the total length of the directory string.

Hope that helps.

Trev answered 20/2, 2016 at 22:58 Comment(0)
P
3

you can use

std::string dir_str = "path/file";
auto pos = dir_str.rfind("/");
if (pos!= std::string::npos) {
  chdir("newpath"+dir_str.substr(pos));
  //...
} else {
//do something;
}

there may be issues such as character / in the file name. but assuming this is just a toy program designed for a simple test it should work.

if you are handling files somewhat seriously (like iterating through a directory recursively) I would recommend using something like boost::file_system.

Purpleness answered 20/2, 2016 at 23:11 Comment(0)
I
1

You can use strtok function from <string.h> to split path components and by the way keep track of each dir in the hierarchy.

#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="/path/to/file";
  char * pch;
  char * temp;
  pch = strtok (str,"/");
  while ( (temp = strtok (NULL, "/") ) != NULL)
  {
    pch = temp;
  }

  printf("The file is: %s", pch);
  return 0;
}
Inert answered 20/2, 2016 at 23:2 Comment(0)
E
1

This might help. What it does, it splits the file path with corresponding directories/files and store the names in a vector.

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    string filePath = "C:\\ProgramData\\Users\\CodeUncode\\Documents";
    vector<string> directories;
    size_t position=0, currentPosition=0;
    
    while(currentPosition != -1)
    {
        currentPosition = filePath.find_first_of('\\', position);
        directories.push_back(filePath.substr(position,currentPosition-position));
        position = currentPosition+1;
    }
    for(vector<string>::iterator it = directories.begin(); it!=directories.end(); it++)
        cout<<*it<<endl;

    return 0;
} 
Erdrich answered 3/10, 2021 at 15:17 Comment(1)
You need to improve your code snippet: Add the required standard library headers, for example. Also, using an int for what should be a size_t (return value of find_first_of) is poor practice.Reconstitute
A
0

To add to plethora of answers, I devised this after looking up stat struct and function:


struct ab_path{
   int delimiter = 0;
   int extension = 0;
   int length    = 0;
   char separator = '\0'; 

   ab_path(){}
   operator bool()
   { return (this->delimiter != 0) | (this->extension != 0) | (this->length != 0) | (this->separator != '\0') ;}
};

bool ab_path( const char* name , struct ab_path* ap ){
   while(1){
      if(name[ap->length] == '\0'){break;}
      if(name[ap->length] == '.') {ap->extension = ap->length;}
      if(name[ap->length] == '/') 
          {ap->delimiter = ap->length; ap->separator = name[ap->length];}
      if(name[ap->length] == '\\') 
          {ap->delimiter = ap->length;ap->separator = name[ap->length];}
      ++ap->length;
   }
   return (bool)ap;
}

struct ab_path ap;
bool valid = ap_path("superb.naming.type", &ap );

But you can rewrite an ap->delimiter to accept container of some sort (std::vector,std::array... ) and store multiple delimiters.

Angelikaangelina answered 30/8, 2019 at 18:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.