如何解决在Powershell遍历子文件夹中合并CSV文件-归档和删除旧文件使用目标CSV的文件夹名称
我想将许多CSV文件合并为一个(几百个文件),以删除所添加CSV的标题行。
由于文件位于几个子文件夹中,因此我需要从根目录遍历所有子文件夹并在其中处理所有CSV。合并之前,我想使用zip删除旧的CSV文件来存档它们。新合并的CSV文件和zip归档文件应像其父文件夹一样命名。
如果再次为同一文件夹启动脚本,则所有已经处理的文件都不应意外损坏或删除。
我不是Powershell专家,所以我一直在从Web的多个资源中复制粘贴内容,并提出了以下解决方案(对不起,如果您知道资源,请不要随意在注释中添加引用)。 / p>
此修补程序代码可以完成任务,但感觉不是很安全。目前,它仅在子文件夹中处理CSV文件。在给定的$targDir
内处理文件也很好。
我想知道它是否可以更紧凑。感谢您提出改进建议。
$targDir = "\\Servername\folder\"; #path
Get-ChildItem "$targDir" -Recurse -Directory |
ForEach-Object { #walkinthrough all subfolder-paths
#
Set-Location -Path $_.FullName
#remove existing AllInOne.csv (targed name for a merged file) in case it has been left over from a previous execution.
$FileName = ".\AllInOne.csv"
if (Test-Path $FileName) {
Remove-Item $FileName
}
#remove existing AllInOne.csv (targed name for archived files) in case it has been left over from a previous execution.
$FileName = ".\AllInOne.zip"
if (Test-Path $FileName) {
Remove-Item $FileName
}
#compressing all csv files in the current path,temporarily named AllInOne.zip. Doing that for each file adding it to the archive (with -Update)
# I wonder if there is a more efficient way to do that.
dir $_.FullName | where { $_.Extension -eq ".csv"} | foreach { Compress-Archive $_.FullName -DestinationPath "AllInOne.zip" -Update}
##########################################################
# This code is basically merging all the CSV files
# skipping the header of added files
##########################################################
$getFirstLine = $true
get-childItem ".\*.csv" | foreach {
$filePath = $_
$lines = $lines = Get-Content $filePath
$linesToWrite = switch($getFirstLine) {
$true {$lines}
$false {$lines | Select -Skip 1}
}
$getFirstLine = $false
Add-Content ".\AllInOne.csv" $linesToWrite
# Output file is named AllInOne.csv temporarily - this is not a requirement
# It was simply easier for me to come up with this temp file in the first place (symptomatic for copy&paste).
}
#########################################################
#deleting old csv files
dir $_.FullName | where { $_.Extension -eq ".csv" -and $_ -notlike "AllInOne.csv"} | foreach { Remove-Item $_.FullName}
# Temporarily rename AllinOne files with parent folder name
Get-ChildItem -Path $_.FullName -Filter *.csv | Rename-Item -NewName {$_.Basename.Replace("AllInOne",$_.Directory.Name) + $_.extension}
Get-ChildItem -Path $_.FullName -Filter *.zip | Rename-Item -NewName {$_.Basename.Replace("AllInOne",$_.Directory.Name) + $_.extension}
}
我一直在Powershell ISE中执行它。该脚本仅用于日常维护,而不是定期执行,因此性能无关紧要。
我宁愿坚持使用尽可能不依赖其他库的脚本(例如Zip)。
解决方法
它可能不是防弹的,但我看到更糟糕的是将脚本拼凑在一起。它肯定会完成您想要的工作,但是这里有一些小的更改会使它变得更短,更难破解。
- 由于所有文件均为CSV文件,并且文件头均相同,因此您可以使用
Import-CSV
将所有文件编译为一个数组。您无需担心剥离标题或意外删除行的情况。
Get-ChildItem "*.csv" | Foreach-Object {
$csvArray += Import-CSV $_
}
然后,您可以只使用Export-CSV -Path $_.FullName -NoTypeInformation
将其全部输出到新的CSV文件中。
- 要检查根文件夹和所有子文件夹,我会将ForEach主循环中的所有行都放入函数中,然后对根文件夹调用一次,并保留所有子文件夹的现有循环。 / li>
function CompileCompressCSV {
param (
[string] $Path
)
# Code from inside the ForEach Loop
}
# Main Script
CompileCompressCSV -Path $targetDir
Get-ChildItem -Path $targetDir -Recurse -Directory | ForEach-Object {
CompileCompressCSV -Path $_.FullName
}
- 这更多是一种样式选择,但是我将以稍微不同的顺序执行此脚本的步骤:
- 获取父文件夹名称
- 删除旧的已编译CSV和ZIPs
- 将CSV编译为数组,并使用父文件夹名称输出
- 将CSV一起压缩成具有父文件夹名称的文件
- 删除所有CSV文件
就我个人而言,我宁愿在第一次使用时正确命名创建的文件,而不要返回并重命名它们,除非绝对没有办法解决。您的情况似乎并非如此,因此您应该能够在第一时间以正确的名称创建它们。