Powershell学习笔记(10):分类整理文件
有快半年时间没写这个系列的文章了,也是由于这半年比较忙碌,除了每周翻译“Windows PowerShell每周提示”之外,在PowerShell上花的时间少了很多。不过相信诸位也从提示中学了不少吧?
今天要谈的是这样一个场景:相信诸位都会遇到分类整理大量文件这个问题。在XP/2003下这件事也许也不太复杂(Vista/2008也改进了很多),我们可以通过在详细信息中点击相关表头对文件排序,然后选取相关文件,然后再新建一个文件夹将文件复制过去。然而当我们遇到需要按时间来整理文件,每天生成的文件都需要建立相对应的文件夹(比如0403),而需要整理的文件包含两个月的内容,那么难道我们要手动创建60个左右的文件夹然后将文件复制过去么?当然如果你没有什么好办法的话也只能用这种最耗精力的办法来整理了……
不过有了PowerShell就完全不同了(在这个问题的某些方面VBScripts实现起来也许也不复杂)。为了说明在这个问题上使用PowerShell的好处,我首先创建了以下演示环境:
首先我们需要找一个测试文件夹,并在该文件夹下建立两个文件夹,分别作为复制源和复制目的地。
然后我们需要找一些测试用的文件,文件可以大一些,因为等下在使用PowerShell做复制的时候我们会使用Write-Progress cmdlet来显示复制进度。(关于这个cmdlet在下周的“Windows PowerShell每周提示”中会有详细说明,敬请期待!)如果你找不到合适的文件,我们也可以手动创建一个。在示例中我用New-Item cmdlet创建了20个8000kb的文本文件,下面是相关代码:
| #声明变量 $content = "a"*8192000 $source = "E:\Test\CopyTest1" $destination = "E:\Test\CopyTest2" $Time = Get-Date #创建文件 for ($i=1;$i -le 20;$i++){ $k = "{0:D2}" -f $i New-Item -Name "Computer-$k.txt" -Path $source -ItemType file -Value $content -ErrorAction SilentlyContinue } Remove-Variable content Remove-Variable k Remove-Variable i |
正如我在代码中注释的那样,这个代码块分两部分,一部分是相关变量的声明,$content是用来填充文本的内容,我用了8192000个a。(题外话,前天是愚人节,在cnBeta上看到一条新闻
愚人节发布的VeryCD电驴下载速度突破带宽限制的秘密里面提到的那个“哪个没良心的搞个那么大的文本文件”,其制作原理如果用PowerShell来做的话,就是以上代码中的方法,先声明一个很长的字符串,然后用New-Item cmdlet的value参数添加到文件中。)$source和$destination则是复制源和复制目的地,没什么需要解释的。$Time变量是得到当前时间,稍后的代码块中会用。
下面的创建文件代码块也不需要做太多解释。首先我使用了循环语句来创建20个文本文件。其次关于$k = "{0:D2} " -f $i 则是用来添加前导0的(1变01)。最后我们将使用过的变量删除。(否则PowerShell会记住相关变量的值,给我们后面的反复测试带来预料之外的效果)
做完以上步骤后,接下来我们通过修改文件的最后修改时间来模拟在不同时间创建的文件。主要使用Set-ItemProperty cmdlet。先来看看代码。
| #修改属性 $colFiles = Get-ChildItem -Path $source foreach ($objItem in $colFiles){ $j+=12 $NewTime = $time.AddHours($j) Set-ItemProperty -Path $objItem.fullname -name LastWritetime -Value $NewTime } Remove-Variable j |
首先我们用Get-ChildItem cmdlet(别名dir)来获得作为复制源的文件夹内所有文件对象的集合。然后我们再次使用foreach循环来修改属性。本例中我修改的是文件的修改日期(LastWriteTime,更多属性和方法可以使用 get-item 相关文件 | Get-Member 来查看。)我们可以使用$time对象的AddHours方法来获得修改过的时间(同样可以使用 $time | Get-Member 来查看其它方法和属性,这里我选择每循环一次就增加12个小时)然后我们使用Set-ItemProperty cmdlet来将修改后的属性写入文件。最后的效果如下图所示:
然后就是正式的复制文件的环节了。不要担心,并不是很复杂的内容。
| #复制文件 $colFiles = Get-ChildItem -Path $source foreach ($objFile in $colFiles){ #$m++ $objItemDate = get-date $objFile.LastWriteTime $oldDay = "{0:D2}" -f $objItemDate.Day $oldMonth = "{0:D2}" -f $objItemDate.Month #$PercentComplete = $m / $colFiles.length * 100 #write-progress -activity "Copy files" -status "Percent: $PercentComplete%" -PercentComplete $PercentComplete New-Item -Name $oldMonth$oldDay -Path $destination -ItemType Directory -ErrorAction SilentlyContinue Copy-Item -Path $objFile.fullname -Destination $destination"\"$oldMonth$oldDay } |
再一次,我在这里使用了foreach循环来处理文件集合$colFiles(注意,之所以我们再次用Get-ChildItem cmdlet来获得相关文件对象的集合,是因为当我们修改过属性后保存在$colFiles中的属性信息已经不是最新的了,所以要重新获取一次)中的每个文件对象$objFile,并获得有关修改时间的相关信息(月和日)。然后将该信息添加上前导0并赋值给$oldDay及$oldMonth变量,随后我们再次使用New-Item cmdlet来建立文件夹,注意和一开始创建文件时的区别(-ItemType参数的值)。然后我们就使用Copy-Item cmdlet来复制对象,这里字符串的组合方式也是PowerShell的一大特色,如果不太熟悉的话,可以留意下,理解上应该并不困难。
注释部分是用来显示复制进度的,如果想要看效果的话可以去掉注释符号(#)并在PowerShell下执行脚本(PowerGUI的Script Editor中会报错)。
至此,关于分类整理文件的一个示例就此完成。纵观整个代码,我们发现其并不复杂,只要善用相关cmdlet、循环语句及相关对象的属性和方法就能完成。当然这只是一个示例,诸位环境中的文件名称可能没有我例子中的那样标准,这时候就需要我们来进行一些判断了(比如Windows PowerShell每周提示(27)中提到Switch语句的相关用法)。
最后希望今天的笔记能给大家带来一点启发。
PS,附件中包含完整脚本代码。