TP 02 - Systems de fichiers et le type Result

Assignment

Vous devez accepter le assignment d'ici et travailler avec ce repository: Lab2

Objectifs

Le but de ce TP est d'apprendre à utiliser

  • Utiliser des fichers
  • Le type Result
  • Utiliser des descripterus de fichers

Travail avec les fichiers en Rust

Pour travailler avec des fichiers on doit utiliser le module fs qui se trouve dans la bilbiotheque standard de Rust.

use std::fs;

Le struct File

Le struct File renvoie un objet donnant accès à un fichier ouvert sur le système de fichiers.

Une instance d'un fichier peut être lue et/ou écrite en fonction des options avec lesquelles elle a été ouverte. Les fichiers implémentent également Seek pour modifier le curseur logique que le fichier contient en interne.

Les fichiers sont automatiquement fermés lorsqu'ils sortent de scope. Les erreurs détectées à la fermeture sont ignorées par l'implémentation de Drop. Utilisez la méthode sync_all si ces erreurs doivent être gérées manuellement.

Créer un fichier

La fonction File::create() ouvre un fichier en mode read-only.

Cette fonction créera un fichier s'il n'existe pas et le tronquera s'il existe.

Selon la plate-forme, cette fonction peut échouer si le chemin d'accès complet au répertoire n'existe pas.

use std::fs::File;
 
fn main() -> std::io::Result<()> {
    let mut f = File::create("foo.txt")?;
    Ok(())
}

Ouvrir un fichier existant

La fonction File::open() tente d'ouvrir un fichier en mode read-only.

use std::fs::File;
 
fn main() -> std::io::Result<()> {
    let mut f = File::open("foo.txt")?;
    Ok(())
}

Lire le contenu d'un fichier

Pour lire à partir d'un fichier, nous utilisons la fonction read_to_string(file_path):

use std::fs;
use std::env;
 
fn main() {
 
    println!("In file {}", file_path);
 
    let contents = fs::read_to_string(file_path)
        .expect("Should have been able to read the file");
 
    println!("With text:\n{contents}");
}

Le struct Metadata

Cette struct renvoie informations de métadonnées sur un fichier.

Ce module contient des méthodes pour récupérer des informations sur un fichier telles que le type de fichier, les autorisations, etc.

Pour consulter toutes les méthodes disponibles, veuillez lire la documentation suivante: Metadata crate!

Le descripteur de fichier

Un descripteur de fichier est un numéro qui identifie de manière unique un fichier ouvert dans le système d'exploitation d'un ordinateur. Il décrit une ressource de données et comment cette ressource peut être accessible.

Lorsqu'un programme demande d'ouvrir un fichier le kernel fait les actions suivantes:

  1. Accorde l'accès
  2. Crée une entrée dans la table de fichiers globale
  3. Fournit au logiciel l'emplacement de cette entrée

Le descripteur est identifié par un entier non négatif unique, tel que 0, 12 ou 567. Au moins un descripteur de fichier existe pour chaque fichier ouvert sur le système.

Pour obtenir le file descriptor d'un fichier on utilise la fonction as_raw_fd().

Le type Result

Le but de ces types de Result est de coder les informations de gestion des erreurs. Result est c'est une énumération avec les variantes:

  • La variante Ok qui indique que l'opération a réussi, et à l'intérieur de Ok se trouve la valeur générée avec succès
  • La variante Err qui signifie que l'opération a échoué, et Err contient des informations sur comment ou pourquoi l'opération a échoué.
enum Result<T, E> {
   Ok(T),
   Err(E),
}

T représente le type de la valeur qui sera renvoyée en cas de réussite dans la variante Ok, et E représente le type d'erreur qui sera renvoyée en cas d'échec dans la variante Err.

Étant donné que Result a ces paramètres de type génériques, nous pouvons utiliser le type Result et les fonctions qui y sont définies dans de nombreuses situations différentes où la valeur réussie et la valeur d'erreur que nous voulons renvoyer peuvent différer.

Voila ici un example d'utilisation de Result pour ouvrir un fichier:

use std::fs::File;
 
fn main() {
    let greeting_file_result = File::open("hello.txt");
 
    let greeting_file = match greeting_file_result {
        Ok(file) => file,
        Err(error) => panic!("Problem opening the file: {:?}", error),
    };
}

Raccourcis: unwrap

La méthode unwrap est une méthode raccourcie implémentée tout comme l'expression de correspondance que nous avons écrite ci-dessus. Si la valeur Result est la variante Ok, unwrap renverra la valeur à l'intérieur de Ok. Si le résultat est la variante Err, unwrap appellera la panic! macro pour nous. Voici un exemple de déballage en action :

use std::fs::File;
 
fn main() {
    let greeting_file = File::open("hello.txt").unwrap();
}

De même, la méthode expect nous permet également de choisir la panic! Message d'erreur. Utiliser expect au lieu de déballer et fournir de bons messages d'erreur peut transmettre votre intention et faciliter la recherche de la source d'une panique. La syntaxe de expect ressemble à ceci :

use std::fs::File;
 
fn main() {
    let greeting_file = File::open("hello.txt")
        .expect("hello.txt should be included in this project");
}

L'operateur '?'

Le ? placé après la définition d'une valeur de résultat pour fonctionner presque de la même manière que l'expression de match que nous avons définies pour gérer les valeurs de résultat dans l'exemple pour unwrap.

Si la valeur du résultat est un Ok, la valeur à l'intérieur de l'Ok sera renvoyée à partir de cette expression et le programme continuera. Si la valeur est une Err, l'Err sera renvoyée par toute la fonction comme si nous avions utilisé le mot-clé return afin que la valeur d'erreur soit propagée au code appelant.

use std::fs::File;
use std::io::{self, Read};
 
fn read_username_from_file() -> Result<String, io::Error> {
    let mut username = String::new();
 
    File::open("hello.txt")?.read_to_string(&mut username)?;
 
    Ok(username)
}

Dans le contexte ci-dessous, le ? à la fin de l'appel File::open renverra la valeur à l'intérieur d'un Ok à la variable username_file. Si une erreur se produit, le ? L'opérateur reviendra plus tôt de toute la fonction et donnera n'importe quelle valeur Err au code appelant. La même chose s'applique au ? à la fin de l'appel read_to_string.

Sugestions

Transformer un buffer (&[u8]) en string (str) peut être fait en utilisant

std::str::from_utf8(&buffer[0..len]).unwrap()

Importations utiles

// utilisé pour les permissions Linux 
use std::os::unix::fs::MetadataExt;
 
// utilisé pour trouver le descripteur de fichier 
use std::os::unix::io::AsRawFd;
 
// utilisé pour la fonction read 
use std::io::Read;

Bibliographie

Exercises

  1. Écrivez un programme qui reçoit en paramètre un dossier. Imprimer le contenu du dossier. Hint: read_dir
  2. Écrivez un programme qui reçoit en argument de ligne de commande un fichier et une tâche. Mettre en œuvre les tâches :
    1. print - imprime le contenu du fichier et le file descriptor
    2. size - imprime la taille du fichier
    3. owner - affiche l'utilisateur (uid) et le groupe (gid) du fichier
    4. mode_number - affiche le mode (permissions) en numero du fichier
    5. type - le type de fichier: dossier, fichier, lien, périphérique caractère, périphérique bloc, …
    6. mode_text - affiche le mode (permissions) en text (rwx…) du fichier
    7. print_buffer - imprimez le contenu du fichier à l'aide des fonctions open et read.
sde2/laboratoare/02_rust.txt · Last modified: 2023/03/14 08:07 by cristiana.andrei
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0