Introdução
Neste laboratório, o módulo std::fs em Rust é apresentado, fornecendo funções para operações no sistema de arquivos. O laboratório apresenta exemplos de várias operações no sistema de arquivos, incluindo a criação de diretórios, a criação de arquivos, a leitura do conteúdo de arquivos, a criação de links simbólicos, a listagem do conteúdo de diretórios, a remoção de arquivos e a remoção de diretórios. Os trechos de código demonstram como realizar essas operações usando as funções do módulo std::fs, e a saída esperada para cada operação é fornecida. Além disso, é mencionada uma implementação alternativa da função cat utilizando a notação ? para tratamento de erros.
Nota: Se o laboratório não especificar um nome de arquivo, você pode usar qualquer nome de arquivo que desejar. Por exemplo, você pode usar
main.rs, compilar e executar comrustc main.rs && ./main.
Operações no Sistema de Arquivos
O módulo std::fs contém várias funções que lidam com o sistema de arquivos.
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::os::unix;
use std::path::Path;
// Uma implementação simples de `% cat path`
fn cat(path: &Path) -> io::Result<String> {
let mut f = File::open(path)?;
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
// Uma implementação simples de `% echo s > path`
fn echo(s: &str, path: &Path) -> io::Result<()> {
let mut f = File::create(path)?;
f.write_all(s.as_bytes())
}
// Uma implementação simples de `% touch path` (ignora arquivos existentes)
fn touch(path: &Path) -> io::Result<()> {
match OpenOptions::new().create(true).write(true).open(path) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}
fn main() {
println!("`mkdir a`");
// Cria um diretório, retorna `io::Result<()>`
match fs::create_dir("a") {
Err(why) => println!("! {:?}", why.kind()),
Ok(_) => {},
}
println!("`echo hello > a/b.txt`");
// A correspondência anterior pode ser simplificada usando o método `unwrap_or_else`
echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`mkdir -p a/c/d`");
// Cria recursivamente um diretório, retorna `io::Result<()>`
fs::create_dir_all("a/c/d").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`touch a/c/e.txt`");
touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`ln -s ../b.txt a/c/b.txt`");
// Cria um link simbólico, retorna `io::Result<()>`
if cfg!(target_family = "unix") {
unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
}
println!("`cat a/c/b.txt`");
match cat(&Path::new("a/c/b.txt")) {
Err(why) => println!("! {:?}", why.kind()),
Ok(s) => println!("> {}", s),
}
println!("`ls a`");
// Lê o conteúdo de um diretório, retorna `io::Result<Vec<Path>>`
match fs::read_dir("a") {
Err(why) => println!("! {:?}", why.kind()),
Ok(paths) => for path in paths {
println!("> {:?}", path.unwrap().path());
},
}
println!("`rm a/c/e.txt`");
// Remove um arquivo, retorna `io::Result<()>`
fs::remove_file("a/c/e.txt").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`rmdir a/c/d`");
// Remove um diretório vazio, retorna `io::Result<()>`
fs::remove_dir("a/c/d").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
}
Aqui está a saída esperada com sucesso:
$ rustc fs.rs && ./fs
$(mkdir a)
$(echo hello > a/b.txt)
$(mkdir -p a/c/d)
$(touch a/c/e.txt)
$(ln -s ../b.txt a/c/b.txt)
$(cat a/c/b.txt)
> hello
$(ls a)
> "a/b.txt"
> "a/c"
$(rm a/c/e.txt)
$(rmdir a/c/d)
E o estado final do diretório a é:
$ tree a
a
|-- b.txt
`-- c
`-- b.txt -> ../b.txt
1 diretório, 2 arquivos
Uma forma alternativa de definir a função cat é com a notação ?:
fn cat(path: &Path) -> io::Result<String> {
let mut f = File::open(path)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
Resumo
Parabéns! Você concluiu o laboratório de Operações no Sistema de Arquivos. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.