Si necesita reducir el consumo de memoria, puede omitir el uso de Get-ChildItem
y en lugar de utilizar un API .NET directamente. Supongo que está en Powershell v2; si es así, primero siga los pasos here para habilitar .NET 4 para cargar en Powershell v2.
En .NET 4 hay algunas buenas API para enumerando archivos y directorios, en lugar de devolverlos en matrices.
[IO.Directory]::EnumerateFiles("C:\logs") |%{ <move file $_> }
Mediante el uso de esta API, en lugar de [IO.Directory]::GetFiles()
, sólo un nombre de archivo será procesado a la vez, por lo que el consumo de memoria debería ser relativamente pequeña.
Editar
También estaba asumiendo que había intentado un enfoque segmentado simple como Get-ChildItem |ForEach { process }
. Si esto es suficiente, acepto que es el camino a seguir.
Pero quiero aclarar un error común: En v2, Get-ChildItem
(o en realidad, el proveedor de sistema de archivos) hace no verdaderamente corriente. La implementación utiliza las API Directory.GetDirectories
y Directory.GetFiles
, que en su caso generarán una matriz de 1.6M elementos antes de que pueda ocurrir cualquier procesamiento. Una vez hecho esto, entonces sí, el resto de la tubería se está transmitiendo. Y sí, esta pieza inicial de bajo nivel tiene un impacto relativamente mínimo, ya que es simplemente una matriz de cadenas, no una matriz de objetos ricos FileInfo
. Pero es incorrecto afirmar que se utiliza la memoria O(1)
en este patrón.
Powershell v3, por el contrario, está basado en .NET 4 y, por lo tanto, aprovecha las API de transmisión que mencioné anteriormente (Directory.EnumerateDirectories
y Directory.EnumerateFiles
). Este es un cambio agradable, y ayuda en escenarios como el tuyo.
Gracias por la solución agradable y simple. Siempre pensé que el pipeline en PowerShell devolvía el resultado completo antes de procesar la siguiente función. –
Esto realmente todavía requiere memoria 'O (n)', pero si resuelve el problema, entonces estoy de acuerdo en que es la mejor solución. – latkin