2015-08-14 83 views
1

我有一个CSV文件中的字符串列表。格式为:使用Powershell替换多个文件和文件夹中的多个字符串

OldValue,NewValue 
223134,875621 
321321,876330 
.... 

并且该文件包含几百行(每个OldValue都是唯一的)。我需要处理多个文件夹&子文件夹中的多个文本文件的更改。我最好猜测文件夹,文件和文本行数 - 15个文件夹,每个文件夹大约150个文本文件,每个文件夹中大约有65,000行文本(每个文本文件400-500行)。

我会在数据上做2遍,除非我可以在一个数据库中完成。第一遍是生成一个文本文件,我将用它作为检查列表来检查我的更改。第二遍是实际进行文件更改。另外,我只想更改字符串出现的文本文件(不是每个文件)。

我正在使用以下Powershell脚本来浏览文件&生成所需更改的列表。脚本运行,但速度非常慢。我还没有在替代逻辑上工作,但我认为它会类似于我所得到的。

# replace a string in a file with powershell 
[reflection.assembly]::loadwithpartialname("Microsoft.VisualBasic") | Out-Null 

Function Search { 
    # Parameters $Path and $SearchString 
    param ([Parameter(Mandatory=$true, ValueFromPipeline = $true)][string]$Path, 
    [Parameter(Mandatory=$true)][string]$SearchString 
) 
    try { 
    #.NET FindInFiles Method to Look for file 

    [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles(
    $Path, 
    [Microsoft.VisualBasic.FileIO.SearchOption]::SearchAllSubDirectories, 
    $SearchString 
    ) 
    } catch { $_ } 

} 


if (Test-Path "C:\Work\ListofAllFilenamesToSearch.txt") { # if file exists 
    Remove-Item "C:\Work\ListofAllFilenamesToSearch.txt" 
    } 
if (Test-Path "C:\Work\FilesThatNeedToBeChanged.txt") { # if file exists 
    Remove-Item "C:\Work\FilesThatNeedToBeChanged.txt" 
    } 

$filefolder1 = "C:\TestFolder\WorkFiles" 
$ftype = "*.txt" 
$filenames1 = Search $filefolder1 $ftype 

$filenames1 | Out-File "C:\Work\ListofAllFilenamesToSearch.txt" -Width 2000 

if (Test-Path "C:\Work\FilesThatNeedToBeChanged.txt") { # if file exists 
    Remove-Item "C:\Work\FilesThatNeedToBeChanged.txt" 
    } 

(Get-Content "C:\Work\NumberXrefList.CSV" |where {$_.readcount -gt 1}) | foreach{ 
    $OldFieldValue, $NewFieldValue = $_.Split("|") 
    $filenamelist = (Get-Content "C:\Work\ListofAllFilenamesToSearch.txt" -ReadCount 5) #| 
    foreach ($j in $filenamelist) { 
    #$testvar = (Get-Content $j) 
    #$testvar = (Get-Content $j -ReadCount 100) 
    $testvar = (Get-Content $j -Delimiter "\n") 
      Foreach ($i in $testvar) 
      { 
      if ($i -imatch $OldFieldValue) { 
       $j + "|" + $OldFieldValue + "|" + $NewFieldValue | Out-File "C:\Work\FilesThatNeedToBeChanged.txt" -Width 2000 -Append 
       } 
      } 
    } 
} 

$FileFolder = (Get-Content "C:\Work\FilesThatNeedToBeChanged.txt" -ReadCount 5) 

Get-ChildItem $FileFolder -Recurse | 
select -ExpandProperty fullname | 
foreach { 
    if (Select-String -Path $_ -SimpleMatch $OldFieldValue -Debug -Quiet) { 
     (Get-Content $_) | 
     ForEach-Object {$_ -replace $OldFieldValue, $NewFieldValue }| 
     Set-Content $_ -WhatIf 
    } 
} 

在上面的代码,我已经试过几件事情与Get-Content - default,与-ReadCount-Delimiter - 在试图避免内存不足的错误。

我控制的唯一的东西是旧的&新替换字符串文件的长度。有没有办法在Powershell中做到这一点?有更好的选择/解决方案吗?我正在运行Windows 7,Powershell 3.0版。

回答

1

您的主要问题是您一遍又一遍地读取文件以更改每个条款。您需要反转替换项的循环和文件循环。另外,预加载csv。例如:

$filefolder1 = "C:\TestFolder\WorkFiles" 
$ftype = "*.txt" 
$filenames = gci -Path $filefolder1 -Filter $ftype -Recurse 

$replaceValues = Import-Csv -Path "C:\Work\NumberXrefList.CSV" 

foreach ($file in $filenames) { 
    $contents = Get-Content -Path $file 

    foreach ($replaceValue in $replaceValues) {  
     $contents = $contents -replace $replaceValue.OldValue, $replaceValue.NewValue 
    } 

    Copy-Item $file "$file.old" 
    Set-Content -Path $file -Value $contents 
} 
相关问题