I am writing a program that can log time & date into an existing log file, without replacing the old records inside but appending new records each time the program runs.
When I searched and discovered the OpenOptions can do the exact things I wanted, and took reference from few sources, so I came out like this:
use chrono::*;
use std::fs::OpenOptions;
fn log_time() -> String {
let local: DateTime<Local> = Local::now();
let date = local.format("%a, %d %b %Y %I:%M:%S %p\n").to_string();
date
}
fn log_time_into_file(filename: String) -> std::io::Result<()> {
let mut f = OpenOptions::new().append(true).create(true).open(filename);
f.write_all(log_time().as_bytes());
Ok(())
}
Upon compiling it threw error message:
error[E0599]: no method named `write_all` found for enum `std::result::Result<std::fs::File, std::io::Error>` in the current scope
Searched for the problem & solution before posting here but no avail. Looked for those tutorial references they can simply get compiled.
I may need help on this, I would like to know did I miss out something or what-else. Thanks!
As for your question, I think you just need to make this change:
// Note the `?` near the end
let mut f = OpenOptions::new().append(true).create(true).open(filename)?;
.open(filename)returns a Result which you have to handle somehow, in case of errors. The ? will return the error if the result is an error, and otherwise the opened file will be assigned to f.
Hi, I have already put the ? near the end of the line:
let mut f = OpenOptions::new().append(true).create(true).open(filename)?;
But I put one more in the next line as well:
f.write_all(log_time().as_bytes())?;
The compiler still complaints about the write_all() method, but with another message now. A full error message here should be more clear:
error[E0599]: no method named `write_all` found for struct `std::fs::File` in the current scope
--> src/main.rs:17:7
|
17 | f.write_all(log_time().as_bytes())?;
| ^^^^^^^^^ method not found in `std::fs::File`
|
::: /home/brian/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/io/mod.rs:1399:8
|
1399 | fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
| --------- the method is available for `std::boxed::Box<std::fs::File>` here
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
1 | use std::io::Write;
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
error: could not compile `rust-first-web`.
To learn more, run the command again with --verbose.
I feel a bit frustrated now, looks like the compiler is telling me the write_all() method belongs to std::fs::File instance, which I did not create an instance of it.
Not sure how can I use OpenOptions instance and append the text in the file.
I guess you tried it before fix to handle the Result. Your original code had 2 problems. One is not handling the Result, and another is not importing the trait Write. use std::io::prelude::* imports bunch of traits including the Write. It's an ordinary module so you can see what items are in it via the document.
Just to elaborate on your own discovery a bit: if you use the standard library’s input or output features, you’ll almost always need to use std::io::prelude::*;. That pulls the BufRead, Read and Write traits into scope, along with their methods, which you’ll usually be using for the actual I/O.
If you search the std:: docs, you’ll see several prelude:: submodules, and the same for many third-party crates. The idea is that you should use _::* these to get the core functionality of the crate or containing module without having to explicitly use every individual component. (The top-level std::prelude is used automatically by the compiler, and provides core stuff like String etc.)