powershell obtenir le nombre de lignes de gros (gros) fichier
l'Un des moyens de ne. de lignes d'un fichier est de cette méthode dans powershell
PS C:UsersPranavDesktopPS_Test_Scripts> $a=Get-Content .sub.ps1
PS C:UsersPranavDesktopPS_Test_Scripts> $a.count
34
PS C:UsersPranavDesktopPS_Test_Scripts>
cependant, quand j'ai un gros fichier texte de 800 Mo, Comment puis-je obtenir le numéro de ligne sans lire tout le fichier ?
la méthode ci-dessus consomme trop de mémoire vive, ce qui provoque un crash du script ou prend trop de temps à terminer.
6 réponses
Utiliser Get-Content -Read $nLinesAtTime
pour lire votre fichier, partie par partie
$nlines = 0;
#read file by 1000 lines at a time
gc $YOURFILE -read 1000 | % { $nlines += $_.Length };
[string]::Format("{0} has {1} lines", $YOURFILE, $nlines)
Et ici est simple, mais lente script pour valider les travaux sur les petites fichier
gc $YOURFILE | Measure-Object -Line
voici un script Powershell que j'ai concocté et qui montre quelques méthodes différentes de comptage de lignes dans un fichier texte, ainsi que le temps et la mémoire nécessaires pour chaque méthode. Les résultats (ci-dessous) montrent des différences claires dans le temps et de mémoire. Pour mes tests, il semble que le bon endroit était Get-Content, en utilisant un réglage ReadCount de 100. Les autres tests nécessitaient beaucoup plus de temps et / ou de mémoire.
#$testFile = 'C:\test_small.csv' # 245 lines, 150 KB
#$testFile = 'C:\test_medium.csv' # 95,365 lines, 104 MB
$testFile = 'C:\test_large.csv' # 285,776 lines, 308 MB
# Using ArrayList just because they are faster than Powershell arrays, for some operations with large arrays.
$results = New-Object System.Collections.ArrayList
function AddResult {
param( [string] $sMethod, [string] $iCount )
$result = New-Object -TypeName PSObject -Property @{
"Method" = $sMethod
"Count" = $iCount
"Elapsed Time" = ((Get-Date) - $dtStart)
"Memory Total" = [System.Math]::Round((GetMemoryUsage)/1mb, 1)
"Memory Delta" = [System.Math]::Round(((GetMemoryUsage) - $dMemStart)/1mb, 1)
}
[void]$results.Add($result)
Write-Output "$sMethod : $count"
[System.GC]::Collect()
}
function GetMemoryUsage {
# return ((Get-Process -Id $pid).PrivateMemorySize)
return ([System.GC]::GetTotalMemory($false))
}
# Get-Content -ReadCount 1
[System.GC]::Collect()
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = 0
Get-Content -Path $testFile -ReadCount 1 |% { $count++ }
AddResult "Get-Content -ReadCount 1" $count
# Get-Content -ReadCount 10,100,1000,0
# Note: ReadCount = 1 returns a string. Any other value returns an array of strings.
# Thus, the Count property only applies when ReadCount is not 1.
@(10,100,1000,0) |% {
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = 0
Get-Content -Path $testFile -ReadCount $_ |% { $count += $_.Count }
AddResult "Get-Content -ReadCount $_" $count
}
# Get-Content | Measure-Object
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = (Get-Content -Path $testFile -ReadCount 1 | Measure-Object -line).Lines
AddResult "Get-Content -ReadCount 1 | Measure-Object" $count
# Get-Content.Count
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = (Get-Content -Path $testFile -ReadCount 1).Count
AddResult "Get-Content.Count" $count
# StreamReader.ReadLine
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = 0
# Use this constructor to avoid file access errors, like Get-Content does.
$stream = New-Object -TypeName System.IO.FileStream(
$testFile,
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::Read,
[System.IO.FileShare]::ReadWrite)
if ($stream) {
$reader = New-Object IO.StreamReader $stream
if ($reader) {
while(-not ($reader.EndOfStream)) { [void]$reader.ReadLine(); $count++ }
$reader.Close()
}
$stream.Close()
}
AddResult "StreamReader.ReadLine" $count
$results | Select Method, Count, "Elapsed Time", "Memory Total", "Memory Delta" | ft -auto | Write-Output
Voici les résultats pour le fichier texte contenant ~95 k lignes, 104 MO:
Method Count Elapsed Time Memory Total Memory Delta
------ ----- ------------ ------------ ------------
Get-Content -ReadCount 1 95365 00:00:11.1451841 45.8 0.2
Get-Content -ReadCount 10 95365 00:00:02.9015023 47.3 1.7
Get-Content -ReadCount 100 95365 00:00:01.4522507 59.9 14.3
Get-Content -ReadCount 1000 95365 00:00:01.1539634 75.4 29.7
Get-Content -ReadCount 0 95365 00:00:01.3888746 346 300.4
Get-Content -ReadCount 1 | Measure-Object 95365 00:00:08.6867159 46.2 0.6
Get-Content.Count 95365 00:00:03.0574433 465.8 420.1
StreamReader.ReadLine 95365 00:00:02.5740262 46.2 0.6
Voici les résultats pour un fichier plus grand (contenant ~285k lignes, 308 Mo):
Method Count Elapsed Time Memory Total Memory Delta
------ ----- ------------ ------------ ------------
Get-Content -ReadCount 1 285776 00:00:36.2280995 46.3 0.8
Get-Content -ReadCount 10 285776 00:00:06.3486006 46.3 0.7
Get-Content -ReadCount 100 285776 00:00:03.1590055 55.1 9.5
Get-Content -ReadCount 1000 285776 00:00:02.8381262 88.1 42.4
Get-Content -ReadCount 0 285776 00:00:29.4240734 894.5 848.8
Get-Content -ReadCount 1 | Measure-Object 285776 00:00:32.7905971 46.5 0.9
Get-Content.Count 285776 00:00:28.4504388 1219.8 1174.2
StreamReader.ReadLine 285776 00:00:20.4495721 46 0.4
la première chose à essayer est de streamer Get-Content
et de construire la ligne de comptage un à la fois, plutôt que de stocker toutes les lignes dans un tableau à la fois. Je pense que cela donnera un comportement de streaming approprié - c.-à-d. le fichier entier ne sera pas en mémoire à la fois, juste la ligne courante.
$lines = 0
Get-Content .\File.txt |%{ $lines++ }
et comme le suggère l'autre réponse, ajouter -ReadCount
pourrait accélérer les choses.
Si cela ne fonctionne pas pour vous (trop lent ou trop de mémoire), vous pouvez aller directement à un StreamReader
:
$count = 0
$reader = New-Object IO.StreamReader 'c:\logs\MyLog.txt'
while($reader.ReadLine() -ne $null){ $count++ }
$reader.Close() # don't forget to do this. Ideally put this in a try/finally block to make sure it happens
Voici une doublure basée sur le post de Pseudothink.
Lignes dans un fichier:
"the_name_of_your_file.txt" |% {$n = $_; $c = 0; Get-Content -Path $_ -ReadCount 1000 |% { $c += $_.Count }; "$n; $c"}
Tous les fichiers du répertoire courant (individuellement):
Get-ChildItem "." |% {$n = $_; $c = 0; Get-Content -Path $_ -ReadCount 1000 |% { $c += $_.Count }; "$n; $c"}
Explication:
"the_name_of_your_file.txt"
- > ne fait rien, fournit juste le nom du fichier pour les prochaines étapes, doit être double Cité |%
-> alias ForEach-Object, itère sur les éléments fournis (un seul dans ce cas), accepte le contenu pipé comme une entrée, l'élément courant est sauvegardé à $_
$n = $_
-> $n que le nom du fichier est sauvegardé pour plus tard à partir de $_
,en fait, cela peut ne pas être nécessaire$c = 0
- > initialisation de $c
count Get-Content -Path $_ -ReadCount 1000
> lire 1000 lignes à partir d'un fichier fourni (voir les autres réponses du sujet) |%
-> foreach faire ajouter des numéros de lignes réellement lire $c
(comme 1000 + 1000 + 123) "$n; $c"
- > une fois le fichier de lecture terminé, imprimer nom de fichier; nombre de lignesGet-ChildItem "."
-> ajoute simplement plus d'éléments dans le tuyau que le nom de fichier
voici quelque chose que j'ai écrit pour essayer de réduire l'utilisation de la mémoire lors de l'analyse de l'espace blanc dans mon fichier txt. Cela dit,l'utilisation de la mémoire toujours obtenir sorte de élevé, mais le processus prend moins de temps à s'exécuter. Juste pour vous donner un peu de fond de mon fichier, le fichier avait plus de 2 millions de dossiers et d'espace blanc à l'avant et à l'arrière de chaque ligne. Je crois que le temps total était de 5 + minutes Veuillez me faire part de vos commentaires s'il y a un moyen d'améliorer le formatage. grâce
$testing = 'C:\Users\something\something\test3.txt'
$filecleanup = gci $testing
foreach ($file in $filecleanup )
{ $file1 = gc $file -readcount 1000 |foreach{ $_.Trim()}
$file1 > $filecleanup}
Voici une solution qui utilise .NET:
[Linq.Enumerable]::Count([System.IO.File]::ReadLines("FileToCount.txt"))
ce n'est pas très interruptible, mais c'est très facile sur la mémoire.