我有一个简单的PowerShell脚本,该脚本将“ false”或“ true”替换为“ 0”或“ 1”:
$InputFolder = $args[0];
if($InputFolder.Length -lt 3)
{
Write-Host "Enter a path name as your first argument" -foregroundcolor Red
return
}
if(-not (Test-Path $InputFolder)) {
Write-Host "File path does not appear to be valid" -foregroundcolor Red
return
}
Get-ChildItem $InputFolder
$content = [System.IO.File]::ReadAllText($InputFolder).Replace("`"false`"", "`"0`"").Replace("`"true`"", "`"1`"").Replace("`"FALSE`"", "`"0`"").Replace("`"TRUE`"", "`"1`"")
[System.IO.File]::WriteAllText($InputFolder, $content)
[GC]::Collect()
这对于几乎所有我需要修改的文件都适用,除了一个808MB CSV以外。 我不知道此CSV中有多少行,因为我什么也打不开。
有趣的是,通过直接通过PowerShell或通过命令提示符手动调用时,PowerShell脚本将成功完成。 当它作为SSIS软件包的一部分启动时,即发生错误。
文件的示例数据:
"RowIdentifier","DateProfileCreated","IdProfileCreatedBy","IDStaffMemberProfileRole","StaffRole","DateEmploymentStart","DateEmploymentEnd","PPAID","GPLocalCode","IDStaffMember","IDOrganisation","GmpID","RemovedData"
"134","09/07/1999 00:00","-1","98","GP Partner","09/07/1999 00:00","14/08/2009 15:29","341159","BRA 871","141","B83067","G3411591","0"
抛出错误消息:
我不受PowerShell约束-我愿意接受其他选择。我以前有一个混杂在一起的C#脚本,但是它死在比这个小的文件上-我不是C#开发人员,所以根本无法调试它。
任何收到的建议或帮助。
答案 0 :(得分:3)
通常,避免一次读取大文件,因为您可能会遇到内存不足的情况。
相反,逐行处理基于文本的文件 -读写。
虽然PowerShell通常在逐行处理(逐对象)方面表现出色,但它的处理速度慢,其中包含多行文件。
直接使用.NET Framework(虽然更为复杂)却可以提供更好的性能。
如果逐行处理输入文件,则不能直接写回它,而必须写入临时输出文件,如果成功,则可以将其替换为输入文件
以下是出于性能原因直接使用.NET类型的解决方案:
# Be sure to use a *full* path, because .NET typically doesn't have the same working dir. as PS.
$inFile = Convert-Path $Args[0]
$tmpOutFile = [io.path]::GetTempFileName()
$tmpOutFileWriter = [IO.File]::CreateText($tmpOutFile)
foreach ($line in [IO.File]::ReadLines($inFile)) {
$tmpOutFileWriter.WriteLine(
$line.Replace('"false"', '"0"').Replace('"true"', '"1"').Replace('"FALSE"', '"0"').Replace('"TRUE"', '"1"')
)
}
$tmpOutFileWriter.Dispose()
# Replace the input file with the temporary file.
# !! BE SURE TO MAKE A BACKUP COPY FIRST.
# -WhatIf *previews* the move operation; remove it to perform the actual move.
Move-Item -Force -LiteralPath $tmpOutFile $inFile -WhatIf
注意:
UTF-8编码,并且重写的文件不具有BOM。您可以通过为.NET方法指定所需的编码来更改此设置。
顺便说一句:使用PowerShell的.Replace()
运算符,可以区分每个输入行上的-replace
调用链,该操作符不区分大小写 ,因此只需要替换 2 :
$line -replace '"false"', '"0"' -replace '"true"', '"1"'
但是,虽然它比 write 短,但实际上比.Replace()
调用链慢,大概是因为-replace
是 regex < / em>为基础,这会引起额外的处理。
答案 1 :(得分:1)
您可以使用 get-content -readcount , Out-file 临时文件读取每行文件,然后删除旧文件和重命名项目< / strong>临时文件中的旧文件名。
需要修复的小东西。这将在文件末尾添加一个新的空行。这将更改编码。您可以尝试获取当前文件的编码,并在 Out-file -encoding
上设置编码function Replace-LargeFilesInFolder(){
Param(
[string]$DirectoryPath,
[string]$OldString,
[string]$NewString,
[string]$TempExtention = "temp",
[int]$LinesPerRead = 500
)
Get-ChildItem $DirectoryPath -File | %{
$File = $_
Get-Content $_.FullName -ReadCount $LinesPerRead |
%{
$_ -replace $OldString, $NewString |
out-file "$($File.FullName).$($TempExtention)" -Append
}
Remove-Item $File.FullName
Rename-Item "$($File.FullName).$($TempExtention)" -NewName $($File.FullName)
}
}
Replace-LargeFilesInFolder -DirectoryPath C:\TEST -LinesPerRead 1 -OldString "a" -NewString "5"