首页 > 解决方案 > 处理可能是驱动器号或连接到其他东西的路径的路径的正确方法是什么?

问题描述

使用以下程序:

use std::path::Path;

fn main() {
    println!("{:?}", Path::new("P:").join("A_B_C\\D\\E\\F\\G.hij"));
}

POSIX 会给你:

"P:/A_B_C\\D\\E\\F\\G.hij"

但 Windows 会给你:

"P:A_B_C\\D\\E\\F\\G.hij"

后者不被认为是预期的路径,至少std::fs::copy.

对于相同的示例:

fn my_function(p: &Path) -> PathBuf {
    p.join("Temp")
}

标签: rust

解决方案


首先,请注意,当您指定不带斜杠符号的驱动器号时,Windows API 会将其解释为驱动器上当前目录的相对路径。即P:andP:\可以引用不同的位置,并且P:file.txt是有效的路径和手段P:\current\dir\file.txt。您可以通过更改目录并从命令提示符调用dir P:dir P:\.

如果您确定要将“P:”解释为根路径,那么您可能应该手动检测它并添加根斜杠,但我认为这是一种不好的做法。

要严格解释路径前缀并构建绝对路径前缀,您可以使用Path::canonicalize()方法,但请记住,它仅适用于目标操作系统中实际存在的驱动器/路径。

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

fn canonical_join<P: AsRef<Path>>(a: P, b: P) -> PathBuf {
    let a = a.as_ref();
    a.canonicalize()
    .unwrap_or(PathBuf::from(a))
    .join(b)
}

fn main() {
    println!("{}", canonical_join("C:", "dir\\file.ext").display());
    println!("{}", canonical_join("C:\\", "dir\\file.ext").display());
    println!("{}", canonical_join("C:/", "dir\\file.ext").display());
}

推荐阅读