Powershell 如何(高效地)将多个小文件的内容(行)与单个大文件的内容(行)匹配并更新/重新创建它们
我已尝试解决以下案例: 许多小文本文件(在子文件夹中)需要其内容(行)与另一个(大)文本文件中存在的行相匹配。然后需要使用这些匹配行更新或复制小文件 我能够为此编写一些运行代码,但我需要对其进行改进或使用一个完整的其他方法,因为它非常慢,需要>40小时才能完成所有文件 我已经有了一个想法,就是使用SQL Server批量导入具有[relative path]、[filename]、[jap content]的单个表中的所有文件,以及具有[jap content]、[eng content]的表中的翻译文件,然后加入[jap content],并使用[relative path]、[filename]将加入的表作为单独的文件批量导出。不幸的是,由于格式和编码问题,我一开始就被卡住了,所以我放弃了它,开始编写PowerShell脚本 现在详细介绍:Powershell 如何(高效地)将多个小文件的内容(行)与单个大文件的内容(行)匹配并更新/重新创建它们,powershell,Powershell,我已尝试解决以下案例: 许多小文本文件(在子文件夹中)需要其内容(行)与另一个(大)文本文件中存在的行相匹配。然后需要使用这些匹配行更新或复制小文件 我能够为此编写一些运行代码,但我需要对其进行改进或使用一个完整的其他方法,因为它非常慢,需要>40小时才能完成所有文件 我已经有了一个想法,就是使用SQL Server批量导入具有[relative path]、[filename]、[jap content]的单个表中的所有文件,以及具有[jap content]、[eng content]的表中
Content:
UTF8 encoded Japanese text that also can contain special characters like \\[*+(), each Line ending with a tabulator character. Sounds like csv files but they don't have headers.
Content:
Again UTF8 encoded Japanese text. Each line formatted like this (without brackets):
[Japanese Text][tabulator][English Text]
Example:
テスト[1] Test [1]
$translationfile = 'B:\Translation.txt'
$inputpath = 'B:\Working'
$translationarray = [System.Collections.ArrayList]@()
$translationarray = @(Get-Content $translationfile -Encoding UTF8)
Get-Childitem -path $inputpath -Recurse -File -Filter *.txt | ForEach-Object -Parallel {
$_.Name
$filepath = ($_.Directory.FullName).substring(2)
$filearray = [System.Collections.ArrayList]@()
$filearray = @(Get-Content -path $_.FullName -Encoding UTF8)
$filearray = $filearray | ForEach-Object {
$result = $using:translationarray -match ("^$_" -replace '[[+*?()\\.]','\$&')
if ($result) {
$_ = $result
}
$_
}
If(!(test-path B:\output\$filepath)) {New-Item -ItemType Directory -Force -Path B:\output\$filepath}
#$("B:\output\"+$filepath+"\")
$filearray | Out-File -FilePath $("B:\output\" + $filepath + "\" + $_.Name) -Force -Encoding UTF8
} -ThrottleLimit 10
我将感谢任何帮助和想法,但请记住,我很少写脚本,所以任何复杂的东西可能会飞到我的头上
感谢诸位,使用a是将纯日语短语映射到双语行的最佳选择
此外,使用.NET API进行文件I/O可以显著加快操作速度
# Be sure to specify all paths as full paths, not least because .NET's
# current directory usually differs from PowerShell's
$translationfile = 'B:\Translation.txt'
$inPath = 'B:\Working'
$outPath = (New-Item -Type Directory -Force 'B:\Output').FullName
# Build the hashtable mapping the Japanese phrases to the full lines.
# Note that ReadLines() defaults to UTF-8
$ht = @{ }
foreach ($line in [IO.File]::ReadLines($translationfile)) {
$ht[$line.Split("`t")[0] + "`t"] = $line
}
Get-ChildItem $inPath -Recurse -File -Filter *.txt | Foreach-Object -Parallel {
# Translate the lines to the matching lines including the $translation
# via the hashtable.
# NOTE: If an input line isn't represented as a key in the hashtable,
# it is passed through as-is.
$lines = foreach ($line in [IO.File]::ReadLines($_.FullName)) {
($using:ht)[$line] ?? $line
}
# Synthesize the output file path, ensuring that the target dir. exists.
$outFilePath = (New-Item -Force -Type Directory ($using:outPath + $_.Directory.FullName.Substring(($using:inPath).Length))).FullName + '/' + $_.Name
# Write to the output file.
# Note: If you want UTF-8 files *with BOM*, use -Encoding utf8bom
Set-Content -Encoding utf8 $outFilePath -Value $lines
} -ThrottleLimit 10
注意:您使用的ForEach Object-Parallel
意味着您使用的是PowerShell[Core]7+,其中无BOM的UTF-8是一致的默认编码(与Windows PowerShell不同,Windows PowerShell中的默认编码差别很大)
因此,除了在
foreach
循环中使用.NET[IO.File]::ReadLines()
API之外,您还可以在-File
参数中使用更具PowerShell风格的语句,以实现高效的逐行文本文件处理。您目前必须进行m*n regex匹配,这将非常缓慢。您应该只解析翻译文件一次以构建哈希表(日文文本作为键,英文文本作为值)。哈希表允许比数组更快的查找(类似于索引SQL表)。使用String.split()
代替regex进一步提高性能。感谢您的评论。我读过哈希表的这一优点,但在实现上遇到了困难。