How can I SIMPLY read a line from stdin and write a (different) line to a local file please? Using async Tokio. (I know it is ridiculous but I can now do it over TLS but not from stdin)
I'm assuming you're talking about stable tokio (v0.1). If so, this is how I would do it:
use std::io::BufReader;
use tokio::io;
use tokio::prelude::{Future, Stream};
use tokio::fs;
fn main() {
// Get tokio's version of stdin, which implements AsyncRead
let stdin = io::stdin();
// Create a buffered wrapper, which implements BufRead
let reader = BufReader::new(stdin);
// Take a stream of lines from this
let lines = io::lines(reader);
let task = lines.take(1) // read one line
.for_each(move |line| {
println!("You typed: {}", line);
// Return a future to complete before reading the next line
// (which will never come anyway)
fs::File::create("/tmp/out.txt")
.and_then(move |f| {
let line = format!("LOG: read a line: {}\n", line);
io::write_all(f, line)
})
.map(drop) // close file when done
})
.map_err(drop);
tokio::run(task);
}
Sorry, I actually meant the latest alpha version but this is helpful nonetheless, thank you. What would be different?
OK, I replaced tokio::run(task); with tokio::runtime::current_thread::Runtime::run(task);
but io::lines or anything similar no longer seems to exist and everything is getting really complicated even for such a simple task.
I'm still pretty new to new tokio, but here's an equivalent example in case it helps. (If any more experienced forum members would like to weigh in on idiomatic code, please do!)
use tokio::prelude::*;
use tokio::codec::{FramedRead, LinesCodec};
use tokio::io;
use tokio::fs::File;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let stdin = io::stdin();
let mut reader = FramedRead::new(stdin, LinesCodec::new());
let line = reader.next().await.transpose()?.unwrap();
println!("You typed: {}", line);
let mut f = File::create("/tmp/out.txt").await?;
let line = format!("LOG: read a line: {}\n", line);
f.write_all(line.as_bytes()).await?;
Ok(())
}
and if I have it within async function and not the main?
You can just simply declare a new codec like that? Well, that is a relief to know.
In general you could stick it in an async fn
and await
on it like anything else.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
do_the_line().await?;
Ok(())
}
async fn do_the_line() -> Result<(), Box<dyn std::error::Error>> {
let stdin = io::stdin();
let mut reader = FramedRead::new(stdin, LinesCodec::new());
let line = reader.next().await.transpose()?.unwrap();
println!("You typed: {}", line);
let mut f = File::create("/tmp/out.txt").await?;
let line = format!("LOG: read a line: {}\n", line);
f.write_all(line.as_bytes()).await?;
Ok(())
}
Great, that is what I wanted!!
... but "next()" does not exist and poll_next() hinted at by the documentation does not seem to exist either
You do need the use
imports I mentioned. next()
is part of StreamExt
, but use tokio::prelude::*
brings that in for you.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.