Why File::create does not work?

Hi,my code like:

pub fn get_parent_dir_in_path_string(path_str: &String) -> String {
    let dir = std::path::Path::new(&path_str);
    let parent_dir = dir.parent().unwrap();
    return parent_dir
        .as_os_str()
        .to_os_string()
        .to_str()
        .unwrap()
        .to_string();
}

pub fn check_dir_or_create(dir_str: String) {
    if !Path::new(&dir_str).exists() {
        std::fs::create_dir_all(&dir_str).unwrap();
    }
}

// file_path: "./user_data/sync/upload_cache/manifest.enc"
pub fn write_bytes_into_file(file_path: String, file_content: &[u8]) -> Result<bool, io::Error> {
    check_dir_or_create(get_parent_dir_in_path_string(&file_path));
  
    // TODO: the file do not exist
    let mut buf = File::create(file_path).expect("11111");
    // let mut buf = File::create(&file_path).expect("11111"); // not work
    // let mut buf = File::create(&file_path[..]).expect("11111"); // not work
    buf.write_all(&file_content)?;

    // TODO: It works ok
    let mut buffer = File::create("./user_data/sync/upload_cache/manifest.enc.json").expect("22222");
    buffer.write_all(&file_content)?;

    Ok(true)
}

The issue in write_bytes_into_file, if I call File::create with function param file_path,the file will not be created. But I use &str,It works ok.

If I add a postfix, it works too. This is strange.

let mut buf = File::create(file_path + &"___").expect("11111");

How can I solve it? Thank you

Are you sure your file_path input is correct? You can use dbg!() macro to inspect variables.

The code looks like it should work, so you're most likely passing wrong value in the file_path argument.

Some less critical points:

  • Use PathBuf instead of String for owned paths.

  • Never use &String for anything, because this type doesn't make sense: it's a read-only view of a string that you specifically require to be growable (but forbidden from growing, because it's borrowed as read only). The correct type for borrowed strings is &str and borrowing String automatically gives it.

  • You don't need to convert to OsString and String. You can return &Path. Generally paths should always be either &Path or PathBuf, and not strings.

  • You can call std::fs::create_dir_all without checking if the path exists. You can even ignore error from this call, because File::create will decide if the dir is there or not.

  • There's std::fs::write() that works in one go (but doesn't create the dir).

1 Like

Thank you.
The file_path param I passed to write_bytes_into_file is ./user_data/sync/upload_cache/manifest.enc, I have print it, it should be fine

I assume the expect() and ? operations don't fail, and the code executes without errors.

Try this:

// canonicalize makes it absolute path
let path = std::fs::canonicalize(&file_path).unwrap(); 
assert!(path.exists());
println!("{} definitely exists", path.display());

here is a fully demo source code, it works. But if I call write_bytes_into_file(file_path, data); with the same params in my project, the dir will be created,but the file won't.

if I change the file extension,like .encr / .enc+ / .en / .e etc. just not .enc, it will works.

It's too strange.

use std::{
    fs::File,
    io::Write,
    path::Path,
    io
};

pub fn get_parent_dir_in_path_string(path_str: &String) -> String {
    let dir = std::path::Path::new(&path_str);
    let parent_dir = dir.parent().unwrap();
    return parent_dir
        .as_os_str()
        .to_os_string()
        .to_str()
        .unwrap()
        .to_string();
}

pub fn check_dir_or_create(dir_str: String) {
    if !Path::new(&dir_str).exists() {
        std::fs::create_dir_all(&dir_str).unwrap();
    }
}

pub fn write_bytes_into_file(file_path: String, file_content: Vec<u8>) -> Result<bool, io::Error>  {
    check_dir_or_create(get_parent_dir_in_path_string(&file_path));

    print!(">>> file_path: {}\n", &file_path);
    print!(">>> file_content: {:?}\n", &file_content);
  
    let mut f = match File::create(&file_path) {
        Ok(file) => file,
        Err(e) => {
            print!(
                "write_bytes_into_file create error, path: {}, error: {}\n",
                &file_path, e
            );
            return Err(e);
        }
    };

    if let Err(e) = f.write_all(&file_content) {
        print!(
            "write_bytes_into_file write_all error, path: {}, error: {}\n",
            &file_path, e
        );
        return Err(e);
    }

    Ok(true)
}

fn main() {
    let data: Vec<u8> = vec![
        123, 34, 100, 97, 116, 97, 86, 101, 114, 115, 105, 111, 110, 34, 58, 49, 44, 34, 110, 111,
        116, 101, 66, 111, 111, 107, 115, 34, 58, 123, 34, 97, 116, 116, 114, 115, 65, 114, 114,
        34, 58, 91, 34, 116, 105, 116, 108, 101, 34, 44, 34, 105, 99, 111, 110, 34, 44, 34, 99,
        104, 105, 108, 100, 67, 111, 117, 110, 116, 34, 44, 34, 104, 97, 115, 104, 101, 100, 83,
        105, 103, 110, 34, 93, 44, 34, 100, 97, 116, 97, 65, 114, 114, 34, 58, 91, 91, 34, 109,
        109, 109, 109, 34, 44, 34, 34, 44, 34, 48, 34, 44, 34, 56, 98, 98, 54, 57, 54, 54, 57, 45,
        53, 52, 56, 56, 45, 52, 101, 57, 102, 45, 97, 100, 57, 55, 45, 101, 56, 98, 50, 52, 55, 57,
        57, 55, 102, 100, 98, 34, 93, 93, 125, 44, 34, 116, 97, 103, 115, 34, 58, 123, 34, 97, 116,
        116, 114, 115, 65, 114, 114, 34, 58, 91, 34, 116, 105, 116, 108, 101, 34, 44, 34, 105, 99,
        111, 110, 34, 44, 34, 104, 97, 115, 104, 101, 100, 83, 105, 103, 110, 34, 93, 44, 34, 100,
        97, 116, 97, 65, 114, 114, 34, 58, 91, 93, 125, 44, 34, 97, 116, 116, 97, 99, 104, 109,
        101, 110, 116, 115, 34, 58, 123, 34, 97, 116, 116, 114, 115, 65, 114, 114, 34, 58, 91, 34,
        102, 105, 108, 101, 78, 97, 109, 101, 34, 44, 34, 104, 97, 115, 104, 101, 100, 83, 105,
        103, 110, 34, 44, 34, 117, 112, 108, 111, 97, 100, 84, 105, 109, 101, 34, 93, 44, 34, 100,
        97, 116, 97, 65, 114, 114, 34, 58, 91, 93, 125, 44, 34, 102, 105, 108, 101, 115, 34, 58,
        123, 34, 97, 116, 116, 114, 115, 65, 114, 114, 34, 58, 91, 34, 102, 105, 108, 101, 78, 97,
        109, 101, 34, 44, 34, 104, 97, 115, 104, 101, 100, 83, 105, 103, 110, 34, 44, 34, 117, 112,
        108, 111, 97, 100, 84, 105, 109, 101, 34, 44, 34, 118, 105, 114, 116, 117, 97, 108, 80, 97,
        116, 104, 34, 93, 44, 34, 100, 97, 116, 97, 65, 114, 114, 34, 58, 91, 93, 125, 125,
    ];

    let file_path = "./user_data/sync_cached/manifest.enc".to_string(); 

    write_bytes_into_file(file_path, data);    
}

This is a correct version of your function:

fn write<P: AsRef<Path>>(path: P, data: &[u8]) -> std::io::Result<()> {
   let path = path.as_ref();
   let _ = std::fs::create_dir_all(path.parent().unwrap());
   std::fs::write(path, data)
}

if this one doesn't work, the error is somewhere else.

Thank you.I just learned rust for 2 weeks, please forgive my stupid code.