Home > other >  std::filesystem::path obtain relative path given a base path without temporary std::string conversio
std::filesystem::path obtain relative path given a base path without temporary std::string conversio

Time:09-09

I am trying to find the relative path of something not from root but from a given path instead, like find the difference of 2 paths using std::filesystem::path objects, for example:

std::filesystem::path path = "/var/log", file = "/var/log/folder1/folder2/log.log";

I was expecting that operator- was implemented for this kind of things so I was expecting something like:

std::filesystem::path rel = file - path; //With a expected result of "folder1/folder2/log.log"

EDIT: After some research and attempts, I finally managed to use std::mismatch like this:

#include <filesystem>
#include <iostream>
#include <algorithm>

int main() {
    std::filesystem::path path, file;
    path = "/var/log";
    file = "/var/log/folder1/folder2/log.log";

    // Temporary string conversion
    std::string path_str = path.string(), file_str = file.string();

    std::filesystem::path str = std::string(std::mismatch(file_str.begin(), file_str.end(), path_str.begin()).first, file_str.end());

    std::cout << "Relative path is " << str.relative_path() << std::endl;

    return 0;
}

It will output: Relative path is "folder1/folder2/log.log"

My question is: Can the same be done without that temporary std::string conversion?

CodePudding user response:

std::mismatch() can help you finding common paths. I assumed there's always a shared path. Starting from the mismatched path element, you can append the rest paths.

Following code printed folde1/folder2/log.log in vs2022.

#include <algorithm>
#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main() {
  try {
    fs::path path = "/var/log";
    fs::path file = "/var/log/folder1/folder2/log.log";

    auto common = std::mismatch(path.begin(), path.end(), file.begin());

    fs::path relative_path;
    for (auto& iter = common.second; iter != file.end();   iter) {
      relative_path /= *iter;
    }

    std::cout << relative_path.string() << std::endl;
  } catch (const std::exception& e) {
    std::cerr << e.what() << std::endl;
    return -1;
  }

  return 0;
}

CodePudding user response:

std::filesystem::relative has an overload that accepts a base path and returns the first argument relative to the second, so all you need is:

auto relative_path = std::filesystem::relative(file, path);

Demo

  •  Tags:  
  • c
  • Related