Je travaille avec des fichiers texte de plusieurs gigaoctets et souhaite effectuer un traitement de flux à l'aide de PowerShell. C'est simple, il suffit d'analyser chaque ligne et d'extraire des données, puis de les stocker dans une base de données.
Malheureusement, get-content | %{ whatever($_) }
semble conserver en mémoire l'ensemble des lignes à ce stade du canal. Il est aussi étonnamment lent et prend beaucoup de temps à tout lire.
Donc ma question est en deux parties:
get-content
semble être 100 fois plus lent qu'un script C #.J'espère que je fais quelque chose de stupide ici, comme rater un paramètre -LineBufferSize
ou quelque chose comme ça ...
Si vous êtes vraiment sur le point de travailler sur des fichiers texte de plusieurs gigaoctets, n’utilisez pas PowerShell. De toute façon, même si vous trouvez un moyen de le lire plus rapidement, le traitement d’un grand nombre de lignes sera lent dans PowerShell et vous ne pouvez pas l’éviter. Même les boucles simples coûtent cher, par exemple pour 10 millions d'itérations (ce qui est bien réel dans votre cas), nous avons:
# "empty" loop: takes 10 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) {} }
# "simple" job, just output: takes 20 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i } }
# "more real job": 107 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i.ToString() -match '1' } }
PDATE: Si vous n'avez toujours pas peur, essayez d'utiliser le lecteur .NET:
$reader = [System.IO.File]::OpenText("my.log")
try {
for() {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
# process the line
$line
}
}
finally {
$reader.Close()
}
PDATE 2
Il y a des commentaires sur un code éventuellement meilleur/plus court. Il n'y a rien de mal avec le code original avec for
et ce n'est pas du pseudo-code. Mais la variante la plus courte (la plus courte?) De la boucle de lecture est
$reader = [System.IO.File]::OpenText("my.log")
while($null -ne ($line = $reader.ReadLine())) {
$line
}
System.IO.File.ReadLines()
est parfait pour ce scénario. Il renvoie toutes les lignes d'un fichier, mais vous permet de commencer immédiatement à parcourir les lignes, ce qui signifie qu'il n'est pas nécessaire de stocker tout le contenu en mémoire.
Nécessite .NET 4.0 ou supérieur.
foreach ($line in [System.IO.File]::ReadLines($filename)) {
# do something with $line
}
Si vous souhaitez utiliser directement PowerShell, consultez le code ci-dessous.
$content = Get-Content C:\Users\You\Documents\test.txt
foreach ($line in $content)
{
Write-Host $line
}