Is a directory (os error 21) when using rust to move a file

55 Views Asked by At

I want to use rust to move a file(or folder) from folder A to another folder, this is my code look like:

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

fn main() {
    let mut file_path = PathBuf::from("/Users/xiaoqiangjiang/apps/a");
    let mut destination_path = PathBuf::from("/Users/xiaoqiangjiang/apps/test/");
    let result = fs::rename(file_path, destination_path);
    if let Err(err) = result {
        print!("{}",err);
    }
}

a is a plain text file. when I run this code in Linux(CentOS 7.8)/macOS(13.3.1 (a) ), shows error:

Is a directory (os error 21)%    

Am I missing something? I have read the docs and example from web, it seems could not work like this. what should I do to fixed this issue? This is the rust version info:

> rustup -V
rustup 1.27.0 (bbb9276d2 2024-03-08)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.77.1 (7cf61ebde 2024-03-27)`
2

There are 2 best solutions below

0
Timsib Adnap On BEST ANSWER

According to the code snippet, you provide, file_path is a file while destination_path is a directory. This is not permitted in rust on linux. According to the docs:

On Unix, if from is a directory, to must also be an (empty) directory. If from is not a directory, to must also be not a directory.

Instead you can do this:

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

fn main() {
    let file_path = PathBuf::from("/Users/xiaoqiangjiang/apps/a");
    let destination_path = PathBuf::from("/Users/xiaoqiangjiang/apps/test/a"); // added file name at the end
    let result = fs::rename(file_path, destination_path);
    if let Err(err) = result {
        println!("{}", err);
    }
}
0
cafce25 On

The relevant part of the documentation is this:

On Unix, if […] from is not a directory, to must also be not a directory. In contrast, on Windows, from can be anything, but to must not be a directory.

I.e. to may not be a directory, but you've passed the name of a directory to the second parameter.

So you'll have to append the file name to the directory name yourself:

let file_path = PathBuf::from("apps/a");
let mut destination_path = PathBuf::from("apps/test/");

destination_path.push(file_path.file_name().unwrap());

let result = fs::rename(file_path, destination_path).unwrap();