How to write a String to file? [duplicate] - rust

This question already has answers here:
What's the de-facto way of reading and writing files in Rust 1.x?
(3 answers)
Closed 6 months ago.
I am very new to Rust, and have the question, how to write a string to a file in Rust. There are plenty of tutorials and documentations out there, how to write an &str type to file, but no tutorial how to write a String type to files. I wrote this code by myself and it compiles, but I always get an "Bad file descriptor (os error 9)". I'm on Linux(Manjaro).
I'm very thankfully for every help I will get.
//Import
use std::fs::File;
use std::io::*;
//Mainfunction
fn main() {
//Programm startet hier | program starts here
println!("Program started...");
// Lesen des Files, createn des Buffers | reading file createing buffer
let mut testfile = File::open("/home/julian/.rust_test/test_0.txt").unwrap();
let mut teststring = String::from("lol");
//Vom File auf den Buffer schreiben | writing from file to buffer
testfile.read_to_string(&mut teststring).unwrap();
//Buffer ausgeben | print to buffer
println!("teststring: {}", teststring);
// Neue Variable deklarieren | declare new variable
let msg = String::from("Writetest tralalalal.");
// msg an ursprünglichen String anhängen | append msg to string
teststring.push_str(&msg);
println!("teststring: {}", teststring);
// Neuen String nach File schreiben | write new sting to file
let eg = testfile.write_all(&teststring.as_bytes());
match eg {
Ok(()) => println!("OK"),
Err(e) => println!("{}",e)
}
println!("Fertig")
}

Your issue is that the file you opened is opened in read-only mode.
As #Herohtar correctly pointed out, from the documentation of File::open():
Attempts to open a file in read-only mode.
What you are trying to do requires read & write mode. There is no pre-made function for that, so you need to build your own using OpenOptions:
//Import
use std::fs::OpenOptions;
use std::io::*;
//Mainfunction
fn main() {
//Programm startet hier | program starts here
println!("Program started...");
// Lesen des Files, createn des Buffers | reading file createing buffer
let mut testfile = OpenOptions::new()
.read(true)
.write(true)
.open("test_0.txt")
.unwrap();
let mut teststring = String::from("lol");
//Vom File auf den Buffer schreiben | writing from file to buffer
testfile.read_to_string(&mut teststring).unwrap();
//Buffer ausgeben | print to buffer
println!("teststring: {}", teststring);
// Neue Variable deklarieren | declare new variable
let msg = String::from("Writetest tralalalal.");
// msg an ursprünglichen String anhängen | append msg to string
teststring.push_str(&msg);
println!("teststring: {}", teststring);
// Neuen String nach File schreiben | write new sting to file
let eg = testfile.write_all(teststring.as_bytes());
match eg {
Ok(()) => println!("OK"),
Err(e) => println!("{:?}", e),
}
println!("Fertig")
}
The rest of your code is pretty much fine.
The only nitpick I have is that testfile.write_all(&teststring.as_bytes()) doesn't make much sense, because as_bytes() already returns a reference, so I removed the & from it.

Related

Edit local yaml file in rust

I'm trying to edit yaml file using serde_yaml but using this i'm only able to edit in stdout but cannot write back to local file(/home/home/.kube/config)
let kubeconfig = "/home/home/.kube/config"
let contents = fs::read_to_string(kubeconfig)
.expect("Something went wrong reading the file");
let mut value: serde_yaml::Value = serde_yaml::from_str(&contents).unwrap();
*value.get_mut("current-context").unwrap() = "new_user".into();
// Below lines shows the edited file in stdout
serde_yaml::to_writer(std::io::stdout(), &value).unwrap();
I did tired as below an other method but had no luck.
let writer = serde_yaml::to_writer(std::io::stdout(), &value).unwrap();
println!("{:?}",writer); // shows ()
serde_yaml::to_writer(writer);
How do i write this edit back to /home/home/.kube/config ?
It seems that you are trying to use to_writer as to_string:
let writer = serde_yaml::to_string(&value).unwrap();
println!("{:?}", writer);
Then you can save the string how you usually would.
Or, alternatively, you could write directly to a file:
let mut file = File::create("/home/home/.kube/config").unwrap();
serde_yaml.to_writer(&mut file, &value);

Rust and Rocket: retrieve raw file content from form-data

Working with Rust and Rocket here. I have an endpoint to upload one file at a time with form-data:
use rocket::form::{Form, FromForm};
use rocket::fs::TempFile;
use std::ffi::OsStr;
use std::path::{Path};
use uuid::Uuid;
#[post("/file_upload", format = "multipart/form-data", data = "<form>")]
pub async fn file_upload(mut form: Form<Upload<'_>>) -> std::io::Result<String> {
// Get raw file
let file_name = form.file.raw_name().unwrap().dangerous_unsafe_unsanitized_raw().as_str();name
// Get extension of file name
let extension = Path::new(file_name).extension().and_then(OsStr::to_str).unwrap();
// Generate new UUID
let id: String = Uuid::new_v4().to_string();
// Build path to save file
let file_path = String::from("media/temp_files") + "/" + &id + "." + extension;
// Save file
form.file.persist_to(file_path).await?;
Ok(String::from("Ok"))
}
This works, but I am mixing persistence, business logic and http infrastructure in the same module.
I want to rely on Rocket only to retrieve the file stream and metadata (file name, size and content type), and pass it to another function that would be in charge or validation, image processing, etc.
I have access to the metadata, but I don't know how to retrieve the Buffered content from the TempFile struct.
// rocket-0.5.0-rc.2/src/fs/temp_file.rs
[…]
pub enum TempFile<'v> {
#[doc(hidden)]
File {
file_name: Option<&'v FileName>,
content_type: Option<ContentType>,
path: Either<TempPath, PathBuf>,
len: u64,
},
#[doc(hidden)]
Buffered {
content: &'v str,
}
}
[…]
I don't see any method returning it.Is there any method I'm missing to retrieve the raw file content? Or maybe there is a different struct/trait in Rocket to achieve this.

Is it possible to access current file name?

Is it possible to access current file name in Rust by
// main.rs
fn main() {
println!("filename: {}", FILE_NAME);
}
?
(This program should print filename: main.rs)
You can use the std::file macro to get the current source filename at the compile time.
let this_file = file!();
If you want to remove the path from the returned filename, you can construct a Path with it and call the file_name method.
let filename_only = Path::new(this_file).file_name().and_then(|s| s.to_str()).unwrap();
Playground

Command panics with process cannot access the file already being used

I'm trying to spawn a CLI in my Rust code via Comand::new. CLI file is extracting from binary files to exe file and then run with Command::new. But It gives 'ERROR: Os { code: 32, kind: Other, message: "The process cannot access the file because it is being used by another process." }' error.
let taskmgr_pid = get_pid_by_name("Taskmgr.exe");
let process_hide = asset::Asset::get("cli.exe").unwrap();
let file_path = "C:\\filepathhere\\cli.exe";
let mut file = File::create(file_path.to_string()).expect("Couldn't create file");
file.write_all(&process_hide);
let res = Command::new(file_path)
.arg(taskmgr_pid.to_string())
.output()
.expect("ERROR");
println!("PID: {}", taskmgr_pid);
println!("{:?}", res);
It's because you didn't close file prior to executing the command. The easiest way to resolve the issue, is to simply drop(file); prior to Command::new().
let mut file = File::create(file_path).expect("unable to create file");
file.write_all(&process_hide).expect("unable to write");
drop(file);
let res = Command::new(file_path)
.arg(taskmgr_pid.to_string())
.output()
.expect("ERROR");

Reading file using Node.js "Invalid Encoding" Error

I am creating an application with Node.js and I am trying to read a file called "datalog.txt." I use the "append" function to write to the file:
//Appends buffer data to a given file
function append(filename, buffer) {
let fd = fs.openSync(filename, 'a+');
fs.writeSync(fd, str2ab(buffer));
fs.closeSync(fd);
}
//Converts string to buffer
function str2ab(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i=0, strLen=str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
append("datalog.txt","12345");
This seems to work great. However, now I want to use fs.readFileSync to read from the file. I tried using this:
const data = fs.readFileSync('datalog.txt', 'utf16le');
I changed the encoding parameter to all of the encoding types listed in the Node documentation, but all of them resulted in this error:
TypeError: Argument at index 2 is invalid: Invalid encoding
All I want to be able to do is be able to read the data from "datalog.txt." Any help would be greatly appreciated!
NOTE: Once I can read the data of the file, I want to be able to get a list of all the lines of the file.
Encoding and type are an object:
const data = fs.readFileSync('datalog.txt', {encoding:'utf16le'});
Okay, after a few hours of troubleshooting a looking at the docs I figured out a way to do this.
try {
// get metadata on the file (we need the file size)
let fileData = fs.statSync("datalog.txt");
// create ArrayBuffer to hold the file contents
let dataBuffer = new ArrayBuffer(fileData["size"]);
// read the contents of the file into the ArrayBuffer
fs.readSync(fs.openSync("datalog.txt", 'r'), dataBuffer, 0, fileData["size"], 0);
// convert the ArrayBuffer into a string
let data = String.fromCharCode.apply(null, new Uint16Array(dataBuffer));
// split the contents into lines
let dataLines = data.split(/\r?\n/);
// print out each line
dataLines.forEach((line) => {
console.log(line);
});
} catch (err) {
console.error(err);
}
Hope it helps someone else with the same problem!
This works for me:
index.js
const fs = require('fs');
// Write
fs.writeFileSync('./customfile.txt', 'Content_For_Writing');
// Read
const file_content = fs.readFileSync('./customfile.txt', {encoding:'utf8'}).toString();
console.log(file_content);
node index.js
Output:
Content_For_Writing
Process finished with exit code 0

Resources