我需要递归计算mp3
和flac
个文件的数量。这是我的代码:
function GetStat()
{
$mp3_count = 0
$flac_count = 0
Set-Variable -Name mp3_count,flac_count -Option AllScope
function getFiles($path)
{
foreach ($item in Get-ChildItem $path)
{
if (Test-Path $item.FullName -PathType Container)
{
GetFiles $item.FullName
}
else
{
if ($item.Extension -eq ".mp3")
{
$mp3_count = $mp3_count + 1
}
if ($item.Extension -eq ".flac")
{
$flac_count = $flac_count + 1
}
}
}
}
getFiles "Y:\music (flac)\Alternative"
$mp3_count
$flac_count
}
我的函数写0, 0
,每次调用函数$mp3_count
时都会重置flac_count
和getFiles()
个变量。
如何修复代码?
答案 0 :(得分:2)
您只需使用A a = new A();
a.m1();
B b = new B();
b.m2();
即可跳过所有这些操作。但是如果你想自己实现递归,这里有几个指针。
我建议不要写入本地范围之外的变量!
使您的递归函数返回一个哈希表,然后将每个递归的值添加到本地哈希表:
Get-ChildItem -Recurse
现在您可以使用以下方法检索每种类型的计数:
function Get-FileCount
{
param(
[Parameter(Mandatory=$false)]
[ValidateScript({Test-Path -LiteralPath $_ -PathType Container})]
[string]$Path = (Resolve-Path $PWD),
[Parameter(Mandatory=$false)]
[string[]]$Extensions = @('flac','mp3')
)
# build local table to hold counts per extension
$ExtensionCount = @{}
# add dot to extensions if missing
$Extensions = $Extensions |ForEach-Object {
$_ -replace '^(?=[^\.])','.'
}
# retrieve all items at current $Path
Get-ChildItem -LiteralPath $Path |ForEach-Object {
# recurse if directory
if($_ -is [System.IO.DirectoryInfo]){
# retrieve count from subfolder
$Subcount = Get-FileCount -Path $_.FullName -Extensions $Extensions
foreach($Extension in $Subcount.Keys){
# add results from recursive call for each identified extension to current count
$ExtensionCount[$Extension] += $Subcount[$Extension]
}
}
elseif($_.Extension -in $Extensions) {
# increment count for the found extension in local $Path
$ExtensionCount[$_.Extension]++
}
}
# return the counting table
return $ExtensionCount
}
如果你想添加新的文件类型,你不需要重写任何东西:
Get-FileCount "Y:\music (flac)\Alternative"
答案 1 :(得分:0)
一般来说,除非你绝对需要,否则不要触及全球范围。你的函数中有很多额外的东西,包括一个不必要的嵌套函数。这是做同样事情的更实用的方法:
# Functions should be named Verb-<Whatever>
function Get-MediaStats ($Path)
{
# Everything that was here was extra and unneeded.
foreach ($item in Get-ChildItem $path -Recurse)
{
if ($item.Extension -eq ".mp3")
{
$mp3_count++
}
if ($item.Extension -eq ".flac")
{
$flac_count++
}
}
# This creates an object... The 'return' or 'write-output' is implied.
[PSCustomObject]@{
'MP3Count' = $mp3_count
'FLACCount' = $flac_count
}
}
# Instead of nested functions you can call the function like so...
# Because it's returning a an object the variable $Result will contain the output.
$Results = Get-MediaStats C:\Path\To\Files
$Results
另请注意,您可以使用$Var++
而不是$Var = $Var + 1
使用对象而不是全局变量在函数之间或函数之外传递东西是正确的方法:
Function Return-Something {
Write-Output 'Something'
}
Function Return-Something {
return 'Something'
}
Function Return-Something {
'Something'
}
Function Return-Something {
[PSCustomObject]@{
'Something' = 'Something'
}
}
如果您$Result = Return-Something
答案 2 :(得分:0)
我会以$items=Get-ChildItem -Recurse -File -Filter "*.mp3" -Path $pathToQuery
递归获取所有文件。然后是用户$items.Count
。您可以针对具有多个扩展程序的一次扫描进行优化,然后在使用Where-Object
进行自定义推理的计数过滤器之前进行优化。例如
$items=Get-ChildItem -Recurse -File -Filter @("*.mp3","*.flac") -Path $pathToQuery
($items|Where-Object {#filter1 reasoning}).Count
($items|Where-Object {#filter2 reasoning}).Count
答案 3 :(得分:0)
Mathias R. Jessen已经提供了一个很好的答案,但是对于简单的事情,您可以将Get-ChildItem
与-Recurse
参数一起使用,并将其传递给Group-Object
以使其更加简单。
Function Get-FileCount{
Param(
[string]$Path,
[string[]]$Extensions = ".MP3",".FLAC"
)
# Sanitize extensions
$Extensions = $Extensions -replace "^(?:.*\.)?([^\.]+)$",'.$1'
#Locate, filter, and group files
Get-ChildItem $Path -Recurse | Where{ $_.Extension -in $extensions } | Group Extension | Select Name,Count
}
然后你可以这样称呼它:
Get-FileCount "Y:\music (flac)\Alternative"
它会输出如下内容:
Name Count
---- -----
.mp3 37
.flac 163