Noções Básicas de Sistemas
10 exemplos para processos, arquivos e interação com o SO usando a biblioteca padrão do Rust.
Pré-requisitos
- Rust 1.97.0 (edição 2024)
- Familiaridade com propriedade e tratamento de erros baseado em
Result
Exemplos Básicos
1. Lendo um Arquivo
use std::fs;
fn main() -> anyhow::Result<()> {
let contents = fs::read_to_string("config.toml")?;
println!("{contents}");
Ok(())
}fs::read_to_stringlida com a decodificação UTF-8- Erros incluem o código de erro do SO via
std::io::Error - Use
readpara dados binários - Prefira
tokio::fsem aplicações assíncronas
2. Escrevendo um Arquivo Atomicamente
use std::fs;
fn write_atomically(path: &str, data: &str) -> std::io::Result<()> {
let tmp = format!("{path}.tmp");
fs::write(&tmp, data)?;
fs::rename(&tmp, path)
}- Escreva em um arquivo temporário, depois renomeie para substituição atômica
renameé atômico no mesmo sistema de arquivos- Falha durante a escrita deixa o original intacto
- Padrão comum para arquivos de configuração e estado
3. Iniciando um Processo Filho
use std::process::Command;
fn main() -> anyhow::Result<()> {
let output = Command::new("git")
.args(["status", "--short"])
.output()?;
println!("{}", String::from_utf8_lossy(&output.stdout));
Ok(())
}output()espera a conclusão e captura os fluxosspawn()retorna umChildpara processos em segundo plano- Defina
current_direenvno builder - Verifique
status.success()antes de confiar no stdout
4. Variáveis de Ambiente
use std::env;
fn main() {
for (key, value) in env::vars() {
if key.starts_with("APP_") {
println!("{key}={value}");
}
}
}env::varretornaResultpara uma única variávelset_varé inseguro em programas multithread (documentado pela edição Rust 2024)- Processos filhos herdam o ambiente do pai
- Use carregamento de configuração tipado para aplicações de produção
5. Metadados de Arquivo
use std::fs;
fn main() -> anyhow::Result<()> {
let meta = fs::metadata("Cargo.toml")?;
println!("size: {} bytes", meta.len());
println!("is_dir: {}", meta.is_dir());
Ok(())
}metadatasegue links simbólicos;symlink_metadatanão- Verifique
permissions()no Unix para bits de modo modified()retorna timestamps do sistema de arquivos- Lide com arquivos ausentes com
?oumatch
6. Travessia de Diretório
use std::fs;
use std::path::Path;
fn list_rs(dir: &Path) -> walkdir::Result<()> {
for entry in walkdir::WalkDir::new(dir) {
let entry = entry?;
if entry.path().extension().is_some_and(|e| e == "rs") {
println!("{}", entry.path().display());
}
}
Ok(())
}- O crate
walkdirsimplifica travessias recursivas - Pule erros de permissão com
WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) - Respeite
.gitignorecom o crateignorepara ferramentas - Evite recursão ilimitada em links simbólicos cíclicos
7. Socket TCP (std)
use std::io::{Read, Write};
use std::net::TcpStream;
fn main() -> anyhow::Result<()> {
let mut stream = TcpStream::connect("127.0.0.1:8080")?;
stream.write_all(b"GET /health HTTP/1.0\r\n\r\n")?;
let mut buf = [0u8; 1024];
let n = stream.read(&mut buf)?;
println!("{}", String::from_utf8_lossy(&buf[..n]));
Ok(())
}- I/O bloqueante é adequado para ferramentas e scripts simples
- Use
TcpListenerpara servidores - Servidores de produção preferem
tokio::net - Defina
read_timeout/write_timeoutpara resiliência
Exemplos Intermediários
8. Pipes de Processo
use std::process::{Command, Stdio};
fn main() -> anyhow::Result<()> {
let mut child = Command::new("grep")
.arg("error")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
child.stdin.as_mut().unwrap().write_all(b"log line\nerror: bad\n")?;
let output = child.wait_with_output()?;
println!("{}", String::from_utf8_lossy(&output.stdout));
Ok(())
}- Pipe stdin/stdout entre o processo pai e o filho
- Sempre
waitouwait_with_outputpara coletar zumbis Stdio::null()descarta fluxos- Base para ferramentas semelhantes a shell
Relacionado: Sinais e Controle de Processos
9. Permissões Unix
#[cfg(unix)]
fn make_executable(path: &str) -> anyhow::Result<()> {
use std::os::unix::fs::PermissionsExt;
let mut perms = std::fs::metadata(path)?.permissions();
perms.set_mode(0o755);
std::fs::set_permissions(path, perms)?;
Ok(())
}- Extensões específicas da plataforma ficam em
std::os - Use
cfg(unix)/cfg(windows)para portabilidade - Documente as expectativas de permissão na ajuda da CLI
- Veja a página multiplataforma para padrões de abstração
Relacionado: Código de Sistemas Multiplataforma
10. Arquivos Temporários
use tempfile::NamedTempFile;
fn main() -> anyhow::Result<()> {
let mut tmp = NamedTempFile::new()?;
std::io::Write::write_all(&mut tmp, b"scratch data")?;
let path = tmp.path().to_owned();
// use path; o arquivo é excluído quando `tmp` é descartado
Ok(())
}- O crate
tempfilelida com caminhos temporários seguros - Arquivos são autoexcluídos ao serem descartados, a menos que persistidos
- Use
tempdir()para diretórios temporários - Prefira arquivos temporários em vez de implementar manualmente
/tmp/myapp-$$
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.