Operaciones del sistema de archivos en Rust

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, se introduce el módulo std::fs de Rust, que proporciona funciones para las operaciones del sistema de archivos. El laboratorio presenta ejemplos de diversas operaciones del sistema de archivos, incluyendo la creación de directorios, la creación de archivos, la lectura del contenido de archivos, la creación de enlaces simbólicos, la lista del contenido de un directorio, la eliminación de archivos y la eliminación de directorios. Los fragmentos de código demuestran cómo realizar estas operaciones utilizando las funciones del módulo std::fs, y se proporciona la salida esperada para cada operación. Además, se menciona una implementación alternativa de la función cat que utiliza la notación ? para el manejo de errores.

Nota: Si el laboratorio no especifica un nombre de archivo, puede utilizar cualquier nombre de archivo que desee. Por ejemplo, puede utilizar main.rs, compilar y ejecutarlo con rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/ControlStructuresGroup(["Control Structures"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/DataTypesGroup -.-> rust/boolean_type("Boolean Type") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/ControlStructuresGroup -.-> rust/for_loop("for Loop") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/mutable_variables -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/boolean_type -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/string_type -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/for_loop -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/function_syntax -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/expressions_statements -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/method_syntax -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} rust/operator_overloading -.-> lab-99277{{"Operaciones del sistema de archivos en Rust"}} end

Operaciones del sistema de archivos

El módulo std::fs contiene varias funciones que se ocupan del sistema de archivos.

use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::os::unix;
use std::path::Path;

// Una implementación simple 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),
    }
}

// Una implementación simple de `% echo s > path`
fn echo(s: &str, path: &Path) -> io::Result<()> {
    let mut f = File::create(path)?;

    f.write_all(s.as_bytes())
}

// Una implementación simple de `% touch path` (ignora archivos 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`");
    // Crea un directorio, devuelve `io::Result<()>`
    match fs::create_dir("a") {
        Err(why) => println!("! {:?}", why.kind()),
        Ok(_) => {},
    }

    println!("`echo hello > a/b.txt`");
    // La coincidencia anterior se puede simplificar utilizando el 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`");
    // Crea un directorio de forma recursiva, devuelve `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`");
    // Crea un enlace simbólico, devuelve `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`");
    // Lee el contenido de un directorio, devuelve `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`");
    // Elimina un archivo, devuelve `io::Result<()>`
    fs::remove_file("a/c/e.txt").unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });

    println!("`rmdir a/c/d`");
    // Elimina un directorio vacío, devuelve `io::Result<()>`
    fs::remove_dir("a/c/d").unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });
}

A continuación se muestra la salida exitosa esperada:

$ 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)

Y el estado final del directorio a es:

$ tree a
a
|-- b.txt
`-- c
    `-- b.txt ->../b.txt

1 directorio, 2 archivos

Una forma alternativa de definir la función cat es con la notación ?:

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)
}

Resumen

¡Felicidades! Has completado el laboratorio de Operaciones del sistema de archivos. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.