Exporter des fichiers vers Microsoft Azure en Rust
Envoyez un fichier local de 16 MiB maximum vers un conteneur Azure Blob Storage privé existant avec ce programme Rust complet. Il envoie une seule requête conditionnelle et refuse de remplacer un blob existant. Les fichiers vides et les données binaires sont des entrées valides.
Cet exemple est destiné à la maintenance et utilise le crate non officiel
azure_storage_blobs 0.21.0.
Dans son avis relatif à l’ancien crate, Microsoft
indique ne pas prévoir de mise à jour de ce crate. Pour de nouvelles applications, évaluez le
SDK officiel azure_storage_blob,
dont les exemples d’authentification utilisent Microsoft Entra ID. Son API diffère de celle de cet
exemple aux versions figées ; changer uniquement le nom de la dépendance ne constitue pas une
migration.
Prérequis
- Un shell Linux avec Bash, Rust, Cargo et l’éditeur de liens système requis par votre installation Rust. Cet exemple a été testé avec Rust et Cargo 1.98.1, en utilisant l’édition 2021. Il s’agit d’un environnement testé, pas d’une version minimale du compilateur. Consultez le guide d’installation de Rust pour installer une chaîne d’outils actuelle.
- Un compilateur C,
pkg-config, ainsi que les bibliothèques et les en-têtes OpenSSL. Le transport TLS par défaut en a besoin sous Linux ; le guide de compilation du crate OpenSSL répertorie les paquets pour les distributions courantes. Installez ces prérequis avant de créer le projet. - Un compte Azure Storage qui autorise déjà l’authentification Shared Key, ainsi que son nom de compte et sa clé d’accès. Cette méthode concerne une intégration Shared Key existante. Microsoft recommande Microsoft Entra ID pour les nouvelles applications ; n’activez pas Shared Key uniquement pour suivre cet exemple.
- Un conteneur privé existant, provisionné séparément. Le programme ne crée pas de conteneurs et ne modifie pas leurs paramètres d’accès. Un conteneur privé exige une autorisation pour lire ses blobs, comme l’explique la documentation Azure sur l’accès anonyme.
- Un fichier ordinaire complet qui restera inchangé pendant l’envoi. Les arguments de la commande, y compris le chemin local, doivent être valides en UTF-8. Utilisez cet exemple de manière séquentielle.
Configurer le projet
Exécutez ce bloc depuis un répertoire accessible en écriture. Il vérifie les outils de compilation
et crée un répertoire ; si azure_export existe déjà, il s’arrête sans entrer dans
ce projet ni le modifier.
(
command -v cargo >/dev/null &&
command -v rustc >/dev/null &&
command -v cc >/dev/null &&
command -v pkg-config >/dev/null &&
pkg-config --exists openssl &&
mkdir azure_export &&
mkdir azure_export/src
) && cd azure_export
Continuez uniquement après la réussite de cette opération. Enregistrez le contenu suivant dans
Cargo.toml. La section vide [workspace] maintient ce projet
séparé d’un espace de travail Cargo englobant. Les fonctionnalités de système de fichiers et d’E/S
de Tokio sont explicites. Conservez le fichier généré Cargo.lock avec votre
application pour garder ses dépendances transitives résolues.
Si la création du répertoire échoue en cours de route, inspectez ce qui a été créé avant de réessayer. Pour une nouvelle tentative, utilisez un nouveau répertoire parent accessible en écriture ; le bloc préserve délibérément les fichiers existants.
[package]
name = "azure_export"
version = "0.1.0"
edition = "2021"
[workspace]
[dependencies]
azure_core = "=0.21.0"
azure_storage = "=0.21.0"
azure_storage_blobs = "=0.21.0"
tokio = { version = "=1.48.0", features = ["fs", "io-util", "macros", "rt-multi-thread", "time"] }
Initialiser le client Azure
Fournissez AZURE_STORAGE_ACCOUNT et AZURE_STORAGE_KEY via votre gestionnaire de
secrets ou l’environnement du processus. La clé est une clé d’accès au compte de stockage, pas une
chaîne de connexion. Le programme appelle StorageCredentials::access_key() ; il ne charge pas de session
Azure CLI. Ne placez pas la clé dans le contrôle de version ni dans les arguments de commandes du
terminal.
Enregistrez le programme complet ci-dessous dans src/main.rs.
Implémentation de l’envoi de fichiers
Le programme lit au maximum 16 MiB plus un octet avant d’envoyer une requête et rejette toute entrée
trop volumineuse. Le plafond de 16 MiB est une règle propre à cet exemple, pas la limite de stockage
d’Azure. Il met l’entrée en mémoire tampon pour une seule opération
put_block_blob ; il ne découpe pas le fichier en blocs intermédiaires et n’effectue
pas d’envois en parallèle. Le nom du blob de destination est un argument distinct du chemin local.
use azure_core::{prelude::IfMatchCondition, RetryOptions};
use azure_storage::StorageCredentials;
use azure_storage_blobs::prelude::{BlobServiceClient, ClientBuilder};
use std::{env, error::Error, path::Path, time::Duration};
use tokio::{fs::File, io::AsyncReadExt, time::timeout};
type AppResult<T> = Result<T, Box<dyn Error + Send + Sync>>;
const MAX_BYTES: u64 = 16 * 1024 * 1024;
async fn upload_file(
service: &BlobServiceClient,
container: &str,
blob_name: &str,
path: &Path,
) -> AppResult<()> {
if container.is_empty() || blob_name.is_empty() {
return Err("Container and blob name must not be empty".into());
}
let file = File::open(path).await?;
if !file.metadata().await?.is_file() {
return Err("Input must be a regular file".into());
}
let mut contents = Vec::new();
file.take(MAX_BYTES + 1).read_to_end(&mut contents).await?;
if contents.len() as u64 > MAX_BYTES {
return Err("Input exceeds the 16 MiB example limit".into());
}
let blob = service.container_client(container).blob_client(blob_name);
blob.put_block_blob(contents)
.content_type("application/octet-stream")
.if_match(IfMatchCondition::NotMatch("*".to_owned()))
.await?;
Ok(())
}
async fn run() -> AppResult<()> {
let args: Vec<String> = env::args().skip(1).collect();
if args.len() != 3 {
return Err("Usage: azure_export CONTAINER BLOB_NAME FILE".into());
}
let account = env::var("AZURE_STORAGE_ACCOUNT")?;
let key = env::var("AZURE_STORAGE_KEY")?;
let credentials = StorageCredentials::access_key(account.clone(), key);
let service = ClientBuilder::new(account, credentials)
.retry(RetryOptions::none())
.blob_service_client();
timeout(
Duration::from_secs(60),
upload_file(&service, &args[0], &args[1], Path::new(&args[2])),
)
.await??;
println!("Upload confirmed.");
Ok(())
}
#[tokio::main]
async fn main() {
if run().await.is_err() {
eprintln!("Upload was not confirmed; check the input, credentials, container, and destination.");
std::process::exit(1);
}
}
Placez le fichier à exporter à l’emplacement data.bin dans le répertoire du
projet. Une fois les informations d’authentification fournies et le conteneur privé
rust-exports déjà disponible, exécutez :
cargo run -- rust-exports 'exports/data.bin' './data.bin'
Cargo résout les dépendances, compile le programme et l’exécute. Les trois arguments sont le
conteneur, le nom du blob de destination et le chemin du fichier local. Placez les chemins contenant
des espaces entre guillemets. Une requête réussie affiche Upload confirmed. et se termine
avec un code de sortie nul. Le blob est nommé exports/data.bin ; la barre oblique fait
partie de son nom, indépendamment de votre arborescence locale. Choisissez un nom de blob sans
barres obliques initiales ou finales : ce SDK supprime ces caractères aux extrémités.
Le délai maximal de 60 secondes couvre la lecture du fichier local et l’envoi par le SDK, après la construction du client. L’installation des dépendances et la compilation par Cargo n’y sont pas incluses. Même un fichier inférieur au plafond de taille peut dépasser ce délai sur une connexion lente.
Gestion des erreurs
Un échec de lecture locale, une configuration manquante, une requête rejetée ou un dépassement de
délai produit un code de sortie non nul et le diagnostic générique
Upload was not confirmed. Le programme évite délibérément d’afficher les informations
d’authentification ou les réponses brutes du SDK. Vérifiez d’abord le fichier local et sa taille,
puis le compte, la clé, le conteneur et la destination sélectionnés. Ce diagnostic seul ne permet
pas d’identifier la raison du refus d’Azure ni de prouver qu’aucun blob n’a été écrit.
L’option IfMatchCondition::NotMatch("*") envoie If-None-Match: *. Le
contrat des en-têtes conditionnels d’Azure
n’autorise l’écriture que si la destination n’existe pas. Relancer la commande pour une destination
existante échoue et préserve son contenu antérieur. Choisissez un autre nom de blob pour un nouvel
export plutôt que de supprimer un objet existant pour faire réussir la commande.
Les nouvelles tentatives du SDK sont désactivées. Après un dépassement de délai, une perte de connexion ou une interruption, Azure peut encore terminer un envoi qu’il a déjà reçu. Arrêter le processus local n’annule pas cette écriture distante. Ne réessayez pas sans vérification et ne considérez pas une liste vide comme la preuve qu’une écriture en attente ne peut pas apparaître plus tard. Inspectez la destination exacte via un client authentifié et vérifiez l’état de la première opération avant de réessayer ; un refus ultérieur peut signifier que le premier envoi a réussi.
Vérifier le résultat stocké
Upload confirmed. signifie que le SDK a reçu une réponse confirmant la réussite de
l’envoi. Le programme ne télécharge pas le blob et ne compare pas les octets stockés. Pour un
export que vous devez vérifier, téléchargez ce blob précis via un client authentifié et comparez
l’intégralité du fichier téléchargé avec la source inchangée, y compris si la source fait zéro
octet. Vérifier uniquement le nom ou le nombre d’octets ne permet pas de détecter un contenu
différent de même taille. Conservez la source locale jusqu’à la fin de la vérification.
Le caractère privé du conteneur est un prérequis distinct : un envoi réussi ne permet pas d’établir sa politique d’accès. Cet exemple ne fournit ni envois avec reprise ni superviseur de transfert pour la production. Pour les fichiers plus volumineux ou l’authentification fondée sur l’identité, partez des exemples d’envoi et d’informations d’authentification du SDK officiel plutôt que de prolonger l’utilisation des anciennes versions figées sans examen de migration.
