Saltar al contenido

Ordenar archivo de texto muy grande en PowerShell

Posterior a de una larga búsqueda de datos dimos con la solución esta contratiempo que tienen muchos de nuestros usuarios. Te dejamos la solución y nuestro objetivo es serte de mucha apoyo.

Solución:

Get-Content es terriblemente ineficaz para leer archivos grandes. Sort-Object no es muy rápido, también.

Establezcamos una línea base:

$sw = [System.Diagnostics.Stopwatch]::StartNew();
$c = Get-Content .log3.txt -Encoding Ascii
$sw.Stop();
Write-Output ("Reading took 0" -f $sw.Elapsed);

$sw = [System.Diagnostics.Stopwatch]::StartNew();
$s = $c | Sort-Object;
$sw.Stop();
Write-Output ("Sorting took 0" -f $sw.Elapsed);

$sw = [System.Diagnostics.Stopwatch]::StartNew();
$u = $s | Get-Unique
$sw.Stop();
Write-Output ("uniq took 0" -f $sw.Elapsed);

$sw = [System.Diagnostics.Stopwatch]::StartNew();
$u | Out-File 'result.txt' -Encoding ascii
$sw.Stop();
Write-Output ("saving took 0" -f $sw.Elapsed);

Con un archivo de 40 MB que tiene 1,6 millones de líneas (compuesto por 100k líneas únicas repetidas 16 veces), este script produce el siguiente resultado en mi máquina:

Reading took 00:02:16.5768663
Sorting took 00:02:04.0416976
uniq took 00:01:41.4630661
saving took 00:00:37.1630663

Totalmente impresionante: más de 6 minutos para ordenar un archivo pequeño. Cada paso se puede mejorar mucho. usemos StreamReader para leer el archivo línea por línea en HashSet que eliminará los duplicados, luego copiará los datos a List y ordenarlo allí, luego usar StreamWriter para volcar los resultados.

$hs = new-object System.Collections.Generic.HashSet[string]
$sw = [System.Diagnostics.Stopwatch]::StartNew();
$reader = [System.IO.File]::OpenText("D:log3.txt")
try 
    while (($line = $reader.ReadLine()) -ne $null)
    
        $t = $hs.Add($line)
    

finally 
    $reader.Close()

$sw.Stop();
Write-Output ("read-uniq took 0" -f $sw.Elapsed);

$sw = [System.Diagnostics.Stopwatch]::StartNew();
$ls = new-object system.collections.generic.List[string] $hs;
$ls.Sort();
$sw.Stop();
Write-Output ("sorting took 0" -f $sw.Elapsed);

$sw = [System.Diagnostics.Stopwatch]::StartNew();
try

    $f = New-Object System.IO.StreamWriter "d:result2.txt";
    foreach ($s in $ls)
    
        $f.WriteLine($s);
    

finally

    $f.Close();

$sw.Stop();
Write-Output ("saving took 0" -f $sw.Elapsed);

este script produce:

read-uniq took 00:00:32.2225181
sorting took 00:00:00.2378838
saving took 00:00:01.0724802

En el mismo archivo de entrada, se ejecuta más de 10 veces más rápido. Todavía estoy sorprendido, aunque se tarda 30 segundos en leer el archivo del disco.

Sección de Reseñas y Valoraciones

Acuérdate de que puedes optar por la opción de agregar una reseña si te ayudó.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *