Powershell : Les nombreuses façons de lire et d’écrire dans des fichiers

L’enregistrement de données dans des fichiers est une tâche très courante lorsqu’on travaille avec PowerShell. Il y a peut-être plus d’options que vous ne le pensez. Commençons par les bases et travaillons sur les options plus avancées.

  • Index
  • Travailler avec des chemins de fichiers
  • Test-Path
  • Split-Path
  • Join-Path
  • Resolve-.Path
  • Enregistrement et lecture de données
    • Redirection de base avec Out-File
    • Enregistrement de données textuelles avec Add-Content
    • Importation de données avec Get-Content -.Raw
    • Enregistrer des données basées sur des colonnes avec Export-CSV
      • -NoTypeInformation
    • Enregistrer des données d’objets riches avec Export-.CliXml
    • Enregistrer des données structurées avec ConvertTo-Json
  • Autres options et détails
    • Get-Content -ReadCount
    • Lectures plus rapides avec System.IO.File
    • Ecritures avec System.IO.StreamWriter
    • Sauvegarde du XML
    • Note rapide sur l’encodage
  • Enveloppement
  • Travail avec les chemins d’accès aux fichiers

    Nous allons commencer par vous montrer les commandes pour travailler avec les chemins d’accès aux fichiers.

    Test-Path

    Test-Path est l’une des commandes les plus connues lorsque vous commencez à travailler avec des fichiers. Elle vous permet de tester un dossier ou un fichier avant d’essayer de l’utiliser.

    If( Test-Path -Path $Path ){ Do-Stuff -Path $Path}

    Split-Path

    Split-Path prendra le chemin complet d’un fichier et vous donnera le chemin du dossier parent.

    PS:> Split-Path -Path 'c:\users\kevin.marquette\documents'c:\users\kevin.marquette

    Si vous avez besoin du fichier ou du dossier à la fin du chemin, vous pouvez utiliser l’argument -Leaf pour l’obtenir.

    PS:> Split-Path -Path 'c:\users\kevin.marquette\documents' -Leafdocuments

    Join-Path

    Join-Path peut joindre des chemins de dossiers et de fichiers ensemble.

    PS:> Join-Path -Path $env:temp -ChildPath testingC:\Users\kevin.marquete\AppData\Local\Temp\testing

    Je l’utilise à chaque fois que je joins des emplacements qui sont stockés dans des variables. Vous n’avez pas à vous soucier de la façon de gérer la barre oblique inverse, car cette fonction s’en occupe pour vous. Si vos variables contiennent toutes deux des barres obliques inversées, cela fait aussi le tri.

    Resolve-Path

    Resolve-Path vous donnera le chemin complet d’un emplacement. La chose importante est qu’il développera les recherches de caractères génériques pour vous. Vous obtiendrez un tableau de valeurs s’il y a plus d’une correspondance.

    Resolve-Path -Path 'c:\users\*\documents'Path----C:\users\kevin.marquette\DocumentsC:\users\Public\Documents

    Ceci énumérera tous les dossiers de documents des utilisateurs locaux.

    J’utilise couramment ceci sur toute valeur de chemin que j’obtiens comme entrée utilisateur dans mes fonctions qui acceptent plusieurs fichiers. Je trouve que c’est un moyen facile d’ajouter le support des caractères génériques aux paramètres.

    Sauvegarde et lecture des données

    Maintenant que nous avons éliminé toutes ces CmdLets d’aide, nous pouvons parler des options dont nous disposons pour sauvegarder et lire les données.

    J’utilise les variables $Path et $Data pour représenter votre chemin de fichier et vos données dans ces exemples. Je fais cela pour garder les échantillons plus propres et cela reflète mieux la façon dont vous les utiliseriez dans un script.

    Direction de base avec Out-File

    PowerShell a été introduit avec Out-File comme moyen d’enregistrer des données dans des fichiers. Voici à quoi ressemble l’aide à ce sujet.

    Get-Help Out-File<#SYNOPSIS Sends output to a file.DESCRIPTION The Out-File cmdlet sends output to a file. You can use this cmdlet instead of the redirection operator (>) when you need to use its parameters.#>

    Pour quiconque vient d’un fichier batch, Out-File est le remplacement de base de l’opérateur de redirection >. Voici un exemple de son utilisation.

    'This is some text' | Out-File -FilePath $Path

    C’est une commande de base et nous l’avons depuis longtemps. Voici un deuxième exemple qui montre certaines de ses limites.

     Get-ChildItem | Select-Object Name, Length, LastWriteTime, Fullname | Out-File -FilePath $Path

    Le fichier résultant ressemble à ceci lorsqu’il est exécuté depuis mon dossier temp:

    Vous pouvez voir que la dernière colonne de valeurs est coupée court. Out-File traite les objets pour la console mais redirige la sortie vers un fichier. Tous les problèmes que vous avez pour obtenir quelque chose à formater dans la console se retrouveront dans votre fichier de sortie. La bonne nouvelle est que nous avons beaucoup d’autres options pour cela que je vais couvrir ci-dessous.

    Enregistrer des données textuelles avec Add-Content

    Je n’utilise personnellement pas Out-File et préfère utiliser les commandes Add-Content et Set-Content. Il existe également une commande Get-Content qui les accompagne pour lire les données des fichiers.

    $data | Add-Content -Path $PathGet-Content -Path $Path

    Add-Content va créer et ajouter des fichiers. Set-Content créera et écrasera des fichiers.

    Ce sont de bonnes commandes polyvalentes tant que les performances ne sont pas un facteur critique dans votre script. Elles sont parfaites pour les requêtes individuelles ou de petit contenu. Pour les grands ensembles de données où les performances comptent plus que la lisibilité, nous pouvons nous tourner vers le framework .Net. Je reviendrai sur celui-ci.

    Importer des données avec Get-Content -Raw

    Get-Content est la commande incontournable pour lire des données. Par défaut, cette commande va lire chaque ligne du fichier. Vous vous retrouvez avec un tableau de chaînes de caractères. Cela permet également de faire passer chacune d’entre elles dans le tuyau de manière agréable.

    Le paramètre -Raw fera entrer l’intégralité du contenu sous la forme d’une chaîne de plusieurs lignes. Cela s’exécute également plus rapidement car moins d’objets sont créés.

    Get-Content -Path $Path -Raw

    Enregistrer des données basées sur des colonnes avec Export-CSV

    Si vous avez un jour besoin d’enregistrer des données pour Excel, Export-CSV est votre point de départ. C’est bon pour stocker un objet ou des données structurées de base qui peuvent être importées plus tard. Le format CSV est constitué de valeurs séparées par des virgules dans un fichier texte. Excel est souvent le visualiseur par défaut des fichiers CSV.

    Si vous voulez importer des données Excel dans PowerShell, enregistrez-les en tant que CSV et vous pouvez ensuite utiliser Import-CSV. Il existe d’autres façons de procéder, mais celle-ci est de loin la plus simple.

    $data | Export-CSV -Path $PathImport-CSV -Path $Path

    -NoTypeInformation

    Export-CSV insérera les informations de type dans la première ligne du CSV. Si vous ne voulez pas cela, alors vous pouvez spécifier le paramètre -NoTypeInformation.

    $data | Export-CSV -Path $Path -NoTypeInformation

    Enregistrer des données d’objets riches avec Export-CliXml

    La commande Export-CliXml permet d’enregistrer des objets complets dans un fichier, puis de les importer à nouveau avec Import-CliXml. Ceci est pour les objets avec des valeurs imbriquées ou des types de données complexes. Les données brutes seront un objet sérialisé verbeux en XML. L’avantage est que vous pouvez sauvegarder un objet dans le fichier et lorsque vous l’importerez, vous récupérerez cet objet.

    Ce format sérialisé n’est pas destiné à être visualisé ou édité directement. Voici à quoi ressemble le fichier date.clixml:

    Ne vous inquiétez pas d’essayer de le comprendre. Vous n’êtes pas destiné à le creuser.

    C’est une autre commande que je ne me retrouve pas à utiliser souvent. Si j’ai un ensemble de données imbriquées ou hiérarchiques, alors JSON est ma façon goto d’enregistrer ces informations.

    Enregistrer des données structurées avec ConvertTo-Json

    Lorsque mes données sont imbriquées et que je peux vouloir les modifier à la main, alors j’utilise ConvertTo-Json pour les convertir en JSON. ConvertFrom-Json le reconvertira en objet. Ces commandes ne permettent pas d’enregistrer ou de lire des fichiers par elles-mêmes. Vous devrez vous tourner vers Get-Content et Set-Content pour cela.

    Il y a une chose importante à noter sur cet exemple. J’ai utilisé un pour mon $Data mais ConvertFrom-Json renvoie un à la place. Ce n’est peut-être pas un problème mais il n’y a pas de solution facile pour le résoudre.

    Notez également l’utilisation du Get-Content -Raw dans cet exemple. ConvertFrom-Json s’attend à une chaîne de caractères par objet.

    Voici le contenu du fichier JSON du dessus:

    { "Address": { "State": "California", "Street": "123 Elm" }}

    Vous remarquerez que cela ressemble à la table de hachage originale. C’est pourquoi JSON est un format populaire. Il est facile à lire, à comprendre et à modifier si nécessaire. Je l’utilise tout le temps pour les fichiers de configuration dans mes propres projets.

    Autres options et détails

    Toutes ces CmdLets sont faciles à travailler. Nous avons également quelques autres paramètres et un accès à .Net pour plus d’options.

    Get-Content -ReadCount

    Le paramètre -ReadCount sur Get-Content définit le nombre de lignes que Get-Content lira en une fois. Il y a certaines situations où cela peut améliorer l’overhead de mémoire pour travailler avec des fichiers plus grands.

    Cela inclut généralement le piping des résultats vers quelque chose qui peut les traiter au fur et à mesure qu’ils arrivent et n’ont pas besoin de conserver les données d’entrée.

    $dataset = @{}Get-Content -Path $path -ReadCount 15 | Where-Object {$PSItem -match 'error'} | ForEach-Object {$dataset += 1}

    Cet exemple comptera combien de fois chaque erreur apparaît dans le $Path. Ce pipeline peut traiter chaque ligne au fur et à mesure qu’elle est lue dans le fichier.

    Vous n’avez peut-être pas de code qui exploite cela souvent, mais c’est une bonne option à connaître.

    Lectures plus rapides avec System.IO.File

    Cette facilité d’utilisation que les CmdLets fournissent peut avoir un petit coût en performance brute. Il est suffisamment faible pour que vous ne le remarquiez pas pour la plupart des scripts que vous faites. Le jour où vous aurez besoin de plus de vitesse, vous vous tournerez vers les commandes natives de .Net. Heureusement, elles sont faciles à utiliser.

    ::ReadAllLines( ( Resolve-Path $Path ) )

    C’est comme Get-Content -Path $Path en ce sens que vous vous retrouverez avec une collection pleine de chaînes de caractères. Vous pouvez également lire les données sous la forme d’une chaîne de caractères à plusieurs lignes.

    ::ReadAllText( ( Resolve-Path $Path ) )

    La $Path doit être le chemin complet, sinon elle essaiera d’enregistrer le fichier dans votre C:\Windows\System32 dossier. C’est pourquoi j’utilise Resolve-Path dans cet exemple.

    Voici un exemple de Cmdlet que j’ai construit autour de ces appels .Net : Import-Content

    Ecritures avec System.IO.StreamWriter

    Sur cette même note, nous pouvons également utiliser System.IO.StreamWriter pour enregistrer des données. Ce n’est pas toujours plus rapide que les Cmdlets natifs. Celui-ci tombe clairement dans la règle selon laquelle si les performances comptent, testez-le.

    System.IO.StreamWriter est également un peu plus compliqué que les CmdLets natifs.

    try{ $stream = ::new( $Path ) $data | ForEach-Object{ $stream.WriteLine( $_ ) }}finally{ $stream.close()}

    Nous devons ouvrir une StreamWriter vers une $path. Ensuite, nous parcourons les données et enregistrons chaque ligne dans la StreamWriter. Une fois que nous avons terminé, nous fermons le fichier. Celui-ci nécessite également un chemin complet.

    J’ai dû ajouter un traitement des erreurs autour de celui-ci pour m’assurer que le fichier était fermé lorsque nous avions terminé. Vous pouvez vouloir ajouter un catch là-dedans pour une gestion personnalisée des erreurs.

    Cela devrait très bien fonctionner pour les données de type chaîne. Si vous avez des problèmes, vous pouvez vouloir appeler la méthode .ToString() sur l’objet que vous écrivez dans le flux. Si vous avez besoin de plus de flexibilité, sachez simplement que vous disposez de tout le framework .Net à ce stade.

    Sauvegarder le XML

    Si vous travaillez avec des fichiers XML, vous pouvez appeler la méthode Save() sur l’objet XML.

    $Xml = "<r><data/></r>"$Path = (join-path $pwd 'File.xml')$Xml.Save($Path)

    Comme les autres méthodes .Net de System.IO, vous devez spécifier le chemin complet du fichier. J’utilise $pwd dans cet exemple parce que c’est une variable automatique qui contient le résultat de Get-Location (chemin local).

    Note rapide sur l’encodage

    L’encodage du fichier est la façon dont les données sont transformées en binaire lorsqu’elles sont enregistrées sur le disque. La plupart du temps, cela fonctionne simplement, à moins que vous ne fassiez beaucoup de travail multiplateforme.

    Si vous rencontrez des problèmes avec l’encodage, la plupart des CmdLets prennent en charge la spécification de l’encodage. Si vous voulez définir l’encodage par défaut pour chaque commande, vous pouvez utiliser la $PSDefaultParameterValues hashtable comme ceci:

    Vous pouvez trouver plus d’informations sur la façon d’utiliser PSDefaultParameterValues dans mon post sur les Hashtables.

    Wrapping up

    Travailler avec des fichiers est une tâche si commune que vous devriez prendre le temps de connaître ces options. J’espère que vous avez vu quelque chose de nouveau et que vous pouvez mettre cela à profit dans vos propres scripts.

    Voici deux fonctions qui mettent en œuvre les idées dont nous avons parlé

    .

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *