Let's say I have a Path
: foo.bar
, and I'd like to append an extension baz
to get: foo.bar.baz
. Right now there seem to be no easy way to do it.
Remember that Path
is analogous to str
and that PathBuf
is likewise analogous to String
, and you can build on it.
How? I can't format!
or append_str
to a PathBuf
. Everything is working on component level, plus couple of methods for extension and file stem. Am I missing something?
Well, if you want it in your format, then you can push and then replace on a .to_string
call to replace /
with .
. I'm on mobile so I can't add a playground example
No. I want a PathBuf
. I need to rename a directory to a ${original_dir}.tmp
, but the original_dir
might already have dots in it.
Why not try the following:
- Get the last component in
path_buf.components()
and cast it'sas_os_str
to an owned string - Add what you want to it
- Call
pop
onpath_buf
- Push your new string onto your
path_buf
This is missing a check to make sure that it is a directory, so be sure that it either is, or run some checks on user input
Edit: it's actually abit more complicated than that because it doesn't go straight to String and instead its os variant, so that's something to keep in mind
Yeah, so I have something like this, but it's terribly clunky. I'm surprised that stdlib provided methods to replace the extension, but not append, which is usually what I would actually like (eg. for tmp files etc)
Oh, what about a cleaner way where you call into_os_string
on the pathbuf and just append and form a new pathbuf?
I know that this isn't very non-clunky but I can't figure out another way without some better context
How do you append to OsString
without converting to Vec<u8>
?
You can push
as better exemplified by the examples on the docs
I've totally missed it. Thank you!
Hi all,
I'm reviving this thread. There's a set_extension
which replaces an extension but no add_extension
.
For example:
use std::path::PathBuf;
let mut path = PathBuf::new();
path.push("/var/log");
path.push("kern.log");
path.set_extension("gz");
println!("{:?}", path);
prints out /var/log/kern.gz
and not /var/log/kern.log.gz
. Any clue ?
Thanks for your help.
I don't believe there's a function for it in std. How about this?
fn add_extension(path: &mut std::path::PathBuf, extension: impl AsRef<std::path::Path>) {
match path.extension() {
Some(ext) => {
let mut ext = ext.to_os_string();
ext.push(".");
ext.push(extension.as_ref());
path.set_extension(ext)
}
None => path.set_extension(extension.as_ref()),
};
}
fn main() {
let mut path = std::path::PathBuf::from("/var/log/kern.log");
add_extension(&mut path, "gz");
assert_eq!(path.as_os_str(), "/var/log/kern.log.gz");
}
If you only need to do it once, or you know for sure the path has an extension, you can do it without a function or in fewer lines.
@Heliozoa Thanks for your contribution.
I'm a little bit reluctant to move to strings, but if this is the only way I'll make it.
BTW, is this add_extension
an opportunity for a PR ?
As long as it's encapsulated in a function there shouldn't be any problem. A PathBuf
is just a newtype wrapper around OsString
which gives us methods specific to file paths, and the standard library deliberately exposes From<OsString>
and Into<OsString>
as an escape hatch for exactly these situations where the provided functionality is missing something.
Yep. I'd create an issue first to gauge interest, probably including a potential implementation, and iron out the edge cases (e.g. what happens if the path is empty, or if it's just pointing to the C:
drive?).
Reviving the thread again.
I went ahead to the issues tracker, but as of time of writing it recommends to start a discussion first, so I did: PathBuf has set_extension but no add_extension. Cannot cleanly turn .tar to .tar.gz - libs - Rust Internals
Reviving this thread again.
The lack of appropriate stdlib function has caused a bug for us so there's very much a need for add_extension
or push_extension
. It's causing real headaches.
There's now been quite a popular discussion with 1.6k views - which has unfortunately been closed due to being stale. What's the next step?
Make a pull request that adds the method.
It's a trivial change, so there's no need to go through the full RFC process or anything complex. From there, whoever is triaging your PR will be able to help you get it into nightly/stable.
This topic was automatically closed 30 days after the last reply. We invite you to open a new topic if you have further questions or comments.