2015-08-14 82 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 
} 
相關問題