Parser un fichier CSV dans Azure Blob Storage

Hao WU
Publié par Hao WU
Catégorie : Azure / Event Grid / Logic Apps
29/04/2024

Introduction

Récemment j’ai travaillé sur un projet pour lequel j’avais besoin de lire le contenu des fichiers CSV et ensuite faire des traitements. Nous stockons ces fichiers dans les conteneurs Azure Blob Storage. Dans cet article, je vais vous montrer la solution que j’ai utilisée pour ce sujet.

 

Problème

Supposons que nous ayons un conteneur « students » sur un Storage Account nommé « stohwu », ce dernier est de type « StorageV2 (general purpose v2) ».

storage account

avec notre conteneur dedans :

blob conteneur

Des fichiers CSV stockant des informations sur des étudiants sont déposés dedans au fil de l’eau. Nous devons lire ces fichiers. Prenons l’exemple d’un fichier Students.CSV :

Student.csv

Chaque ligne contient l’information d’un étudiant, séparé par des tabulations, chaque ligne est terminée par « CRLF ».

Quand un fichier est déposé sous forme de blob, comment peut-on déclencher notre processus de lecture et traitement ? Le contenu du fichier est une chaîne de caractères, comment le transformer pour la lecture ?

 

Solution et Démo

J’ai décidé d’utiliser une Azure Logic App afin de manipuler ces fichiers. Nous allons donc voir, dans un premier temps, comment déclencher ce composant au moment de la dépose d’un blob, puis, dans un second temps, comment le manipuler.

 

Trigger

Lorsque nous déposons un fichier dans un conteneur, nous avons le choix d’utiliser un Blob Trigger ou un Event Grid Trigger pour détecter cet évènement et déclencher le processus. Cependant, le Blob Trigger a des limitations :

  • Il ne supporte pas « Blob-only storage account ». Ceci impose l’utilisation d’un « General Purpose Storage Account ».
  • Il déclenche la récupération de tous les blobs dans le conteneur. C’est mal adapté dans le cas où on ne souhaite récupérer que les nouveaux blobs créés.
  • Il fait du polling, la fréquence dépend donc du paramétrage. Une fréquence trop élevée va alourdir la facture inutilement. Une fréquence trop faible impliquera potentiellement un temps de traitement trop long.

Pour répondre à ces limitations nous allons profiter du trigger Event Grid. Le déclenchement sera instantané, à la création du blob. De plus, il sera plus simple de cibler uniquement les nouvelles créations.

Créons d’abord un Event Grid System Topic de cette manière :

Event Grid

Avec un Topic Type “Storage Account (Blob &GPv2)”. Voici donc le Topic créé :

Event Grid Topic

Je choisi l’Event Grid Trigger pour notre Logic App, renseignons le Ressource Type avec « Microsoft.Storage.StorageAccounts » et l’Event Type « Microsoft.Storage.BlobCreated ». J’ajoute également les Prefix Filter et Suffix Filter pour raffiner les conditions de déclenchement. Les configurations sont les suivantes :

Logic App Configuration

Get Blob Content

Par la suite on va créer l’opération « Get blob content using path ». Le « path » est renseigné à l’aide des informations venant du trigger. Cela permet d’être générique.

Logic App Configuration

Voici le contenu exact du Blob Path :

concat('/students/',split(triggerBody()?['data']?['url'],'/')?[4])

J’obtiens donc, après exécution de la Logic App, la sortie suivante :

blob content

 

Parser le fichier

Regardons le body obtenu dans le “Get blob Content” :

"body": "S1\tEnzo\tMartin\r\nS2\tLisa\tBernard\r\nS3\tPaul\tDubois\r\nS4\tMarc\tRichard\r\n"

Nous allons utiliser une Azure Function pour parser le contenu et le transférer en json.

Voici notre modélisation de l’objet « Student » :

namespace MW.Blog.HWU.Model
{
    public class Students
    {
        public List<Student> listStudents { get; set; }
        public Students()
        {
            listStudents = new List<Student>();
        }
    }
    public class Student
    {
        public string Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

et notre Azure Function :

[FunctionName("ParserStudentsFileToJson")]
public static Students RunParser(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest request,
    ILogger log)
{
    string reqBody = new StreamReader(request.Body).ReadToEnd();
    dynamic data = JsonConvert.DeserializeObject(reqBody);
    string fileContent = data?.fileContent;
    Students studentsRes = new Students();

    string[] Lines = new string[] { };
    if (fileContent.IndexOf("\r\n") > 0)
    {
        Lines = fileContent.Split("\r\n");
    }
    foreach (var l in Lines)
    {
        if (l.Trim().Length > 0) // ignore empty line
        {
            string[] items = l.Split("\t");
            Student stu = new Student
            {
               Id = items[0],
               FirstName = items[1],
               LastName = items[2]
            };                   
            studentsRes.listStudents.Add(stu);
        }
    }
    return studentsRes;
}

En résume, notre Logic App se présente comme ça :

logic app overview

Faisons un test, une fois qu’un fichier Student.CSV est déposé dans le conteneur, notre process est déclenché immédiatement et on voit que le contenu est transféré après l’Azure Function :

Azure Function Output

Le tour est joué ! Une fois nous avons transformé le contenu en json, nous pouvons en faire ce que l’on veut.

 

Conclusion

Dans cet article, nous avons déclenché la lecture d’un fichier csv à sa création dans notre Storage Account à l’aide d’un Event Grid Trigger. Pour aller plus loin, on pourrait envisager de se passer de la Logic App en utilisant directement un Event Handler dans notre Azure Function.