70

Given a relative path:

PathBuf::from("./cargo_home")

Is there a way to get the absolute path?

Eduardo Bautista
  • 1,340
  • 2
  • 10
  • 22
  • 3
    Note that "[since many file systems in Linux support hard links, any given directory can have a number of different absolute paths."](http://stackoverflow.com/a/2341847/155423) – Shepmaster May 28 '15 at 15:54

4 Answers4

92

Rust 1.5.0 added std::fs::canonicalize, which sounds pretty close to what you want:

Returns the canonical form of a path with all intermediate components normalized and symbolic links resolved.

Note that, unlike the accepted answer, this removes the ./ from the returned path.


A simple example from my machine:

use std::fs;
use std::path::PathBuf;

fn main() {
    let srcdir = PathBuf::from("./src");
    println!("{:?}", fs::canonicalize(&srcdir));

    let solardir = PathBuf::from("./../solarized/.");
    println!("{:?}", fs::canonicalize(&solardir));
}
Ok("/Users/alexwlchan/Developer/so-example/src")
Ok("/Users/alexwlchan/Developer/solarized")
alexwlchan
  • 5,699
  • 7
  • 38
  • 49
  • 39
    There are a couple problems with canonicalize. 1) It resolves symlinks to a canonical path, so it must access the file system. This can impact performance. 2) It fails if the file does not exist. So you can not use fs::canonicalize() on a path that does not (yet) exist. – Cody Casterline Nov 21 '16 at 16:27
  • 2
    I have run into issues using fs::canonicalize (running on Mac OS X), is it guaranteed that it will return an absolute path, or it just "canonicalizes" the relative path? e.g. "../peer-dir/../second-peer-dir" --> "../second-peer-dir" – Andrew Mackenzie Nov 26 '17 at 08:13
  • 2
    Another possible pitfall on Windows: `canonicalize` (as of Rust 1.31) adds the *Extended length path* prefix ` \\?\ ` to the path (see https://learn.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maxpath). Make sure the consumer of the canonicalized path is aware of that. – Tomáš Dvořák Dec 18 '18 at 13:27
  • Please note that fs::canonicalize uses UNC path on Windows. So the result may not be what you want on Windows. See https://github.com/rust-lang/rust/issues/42869 – rhysd Dec 26 '18 at 03:28
  • There is also the alias method `canonicalize` that you can use directly: `srcdir.canonicalize()`. – hsandt Apr 25 '19 at 23:02
40

You can do this quite nicely using the path-clean crate and std::env::current_dir. The benefit of this method over the other answers is that it resolves . and .. and it works even when the path doesn't exist.

use std::env;
use std::io;
use std::path::{PathBuf, Path};

use path_clean::PathClean;

pub fn absolute_path(path: impl AsRef<Path>) -> io::Result<PathBuf> {
    let path = path.as_ref();

    let absolute_path = if path.is_absolute() {
        path.to_path_buf()
    } else {
        env::current_dir()?.join(path)
    }.clean();

    Ok(absolute_path)
}
Caleb Bassi
  • 501
  • 5
  • 4
15

If I understand the PathBuf documentation correctly it does not treat "./" as a special start to a path that says its relative.

You can however turn a relative path into an absolute one with std::env::current_dir:

let relative_path = PathBuf::from("cargo_home");
let mut absolute_path = try!(std::env::current_dir());
absolute_path.push(relative_path)

This assumes that your relative path is relative to your current directory.

FlyingFoX
  • 3,379
  • 3
  • 32
  • 49
  • 7
    This doesn't appear to do *quite* the same thing as the asker may have intended. If you use this to "absolutise" `./x`, you end up with the `.` as part of the result, whereas they might be expecting it *not* to show up. The distinction is important if you're trying to get a (within the limits imposed by hard links) canonical path to a file. – DK. May 29 '15 at 14:52
  • 1
    I wouldn't *delete* your answer; it still can work in some of the conditions that the other answer fails (no file created, for example). – Shepmaster Jan 17 '17 at 19:16
  • How to turn `absolute_path` into a string for display or format? – Petrus Theron Nov 24 '18 at 09:27
7

There is https://crates.io/crates/path-absolutize now, for handling non-existent paths.

xixixao
  • 481
  • 6
  • 16