如何在PowerShell中迭代包含大量文件的文件夹?

T.H*_*.Ho 8 powershell

我正在尝试编写一个脚本,该脚本将遍历文件夹中的160万个文件,并根据文件名将它们移动到正确的文件夹中.

原因是NTFS无法处理单个文件夹中的大量文件而不会降低性能.

脚本调用"Get-ChildItem"来获取该文件夹中的所有项目,正如您所料,这会消耗大量内存(大约3.8 GB).

我很好奇是否有其他方法可以遍历目录中的所有文件而不占用太多内存.

man*_*lds 13

如果你这样做

$files = Get-ChildItem $dirWithMillionsOfFiles
#Now, process with $files
Run Code Online (Sandbox Code Playgroud)

你将面临记忆问题.

使用PowerShell管道处理文件:

Get-ChildItem $dirWithMillionsOfFiles | %{ 
    #process here
}
Run Code Online (Sandbox Code Playgroud)

第二种方式将消耗更少的内存,理想情况下不应超过某一点.

  • 这实际上仍然需要'O(n)`内存,但如果它解决了问题,那么我同意它是最好的解决方案. (2认同)

lat*_*kin 13

如果需要减少内存占用,可以跳过使用Get-ChildItem,而不是直接使用.NET API.我假设您使用的是Powershell v2,如果是这样,请首先按照此处的步骤启用.NET 4以加载Powershell v2.

在.NET 4中,有一些很好的API用于枚举文件和目录,而不是在数组中返回它们.

[IO.Directory]::EnumerateFiles("C:\logs") |%{ <move file $_> }
Run Code Online (Sandbox Code Playgroud)

通过使用此API,而不是[IO.Directory]::GetFiles()一次只处理一个文件名,因此内存消耗应该相对较小.

编辑

我还假设你尝试过一种简单的流水线方法Get-ChildItem |ForEach { process }.如果这足够了,我同意这是要走的路.

但我想澄清一个常见的误解:在v2中,Get-ChildItem(或者实际上,FileSystem提供者)并没有真正流式传输.实现使用的API Directory.GetDirectoriesDirectory.GetFiles,而你的情况会产生之前,就可能出现的任何处理中的1.6M-元件阵列.一旦完成,那么是,管道的其余部分是流式传输.是的,这个初始的低级片段影响相对较小,因为它只是一个字符串数组,而不是一个富FileInfo对象数组.但声称O(1)在此模式中使用内存是不正确的.

相比之下,Powershell v3是基于.NET 4构建的,因此利用了我在上面提到的流API(Directory.EnumerateDirectoriesDirectory.EnumerateFiles).这是一个很好的改变,并有助于你的场景.

  • 看我的编辑.`get-childitem | foreach {...}`只是伪流,技术上仍需要"O(n)"内存. (2认同)