我有一個場景,我需要編輯非常大的檔案,最終結果相當簡單,但實作它對我的計算機和記憶體來說有點拖累。由于下游系統,我無法加載重復檔案(根據計算的哈希)兩次。我的解決方法是將第一條實際的行/記錄移動到檔案的末尾而不更改任何其他內容。這種方法(在下面的方法 1 中顯示)適用于足夠小的檔案,但現在我有非常大的檔案。所以我開始研究下面的方法 2,但我還沒有完全弄清楚如何將輸入檔案中的行流式傳輸到輸出檔案中。
#Method 1
$Prefix = Read-Host -Prompt "What do you want to use as the prefix for the updated file names? (The number 1 is the default)"
If ([string]::IsNullOrEmpty($Prefix)){$Prefix = '1_'}
If($Prefix[-1] -ne '_'){$Prefix = "$($Prefix)_"}
$files = (Get-ChildItem -LiteralPath $PWD -Filter '*.csv' -File)
Foreach ($inputFile in $files){
$A = Get-Content $inputFile
$Header = $A[0]
$Data = $A[2..($A.Count-1)]
$Footer = $A[1]
$Header, $Data, $Footer | Add-Content -LiteralPath "$($inputFile.DirectoryName)\$($Prefix)$($inputFile.BaseName).csv"
}
#Work-in-progress Method 2
$inputFile = "\Input.csv"
$outputFile = "\Output.csv"
#Create StringReader
$sr = [System.IO.StringReader]::New((Get-Content $inputFile -Raw))
#Create StringWriter
$sw = [System.IO.StringWriter]::New()
#Write the Header
$sw.Write($sr.ReadLine())
#Get the first actual record as a string
$lastLine = $sr.ReadLine()
#Write the rest of the lines
$sw.Write($sr.ReadToEnd())
#Add the final line
$sw.Write($lastLine)
#Write everything to the outputFile
[System.IO.File]::WriteAllText($outputFile, $sw.ToString())
Get-Content:
Line |
5 | $sr = [System.IO.StringReader]::New((Get-Content $inputFile -Raw))
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Insufficient memory to continue the execution of the program.
MethodInvocationException:
Line |
5 | $sr = [System.IO.StringReader]::New((Get-Content $inputFile -Raw))
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling ".ctor" with "1" argument(s): "Value cannot be null. (Parameter 's')"
例如,我在理解 aStringWriter本身和 a之間的區別時遇到了一些麻煩StringBuilder- 為什么我會選擇StringWriter像我一樣使用 a 而不是直接使用 a StringBuilder?最重要的是,方法 2 的當前迭代需要比我的系統更多的記憶體,并且它實際上并沒有將字符/行/資料從輸入檔案流式傳輸到輸出檔案。是否有用于檢查我忽略的記憶體的內置方法,或者是否有更好的方法來實作我的目標?
uj5u.com熱心網友回復:
PowerShell Pipeline的好處在于它天生就是流式傳輸的。
如果使用正確,意思是:
- 不要將任何管道結果分配給變數,并且
- 不要使用括號
因為那會阻塞管道。
在你的情況下:
$Prefix = Read-Host -Prompt "What do you want to use as the prefix for the updated file names? (The number 1 is the default)"
If ([string]::IsNullOrEmpty($Prefix)){$Prefix = '1_'}
If($Prefix[-1] -ne '_'){$Prefix = "$($Prefix)_"}
Get-ChildItem -LiteralPath $PWD -Filter '*.csv' -File |
Import-Csv |ForEach-Object -Begin { $Index = 0 } -Process {
if ($Index ) { $_ } else { $Footer = $_ }
} -End { $Footer } |
Export-Csv -LiteralPath "$($inputFile.DirectoryName)\$($Prefix)$($inputFile.BaseName).csv"
uj5u.com熱心網友回復:
這就是您的代碼使用StreamReaderand的樣子StreamWriter:
Get-ChildItem -LiteralPath $PWD -Filter '*.csv' -File | ForEach-Object {
try {
$path = "$($_.DirectoryName)\$Prefix$($_.BaseName).csv"
$writer = [IO.StreamWriter] $path
$stream = $_.OpenRead()
$reader = [IO.StreamReader] $stream
$header = $reader.ReadLine()
while(-not $reader.EndOfStream) {
$writer.WriteLine($reader.ReadLine())
}
$writer.WriteLine($header)
}
finally {
$stream, $reader, $writer | ForEach-Object Dispose
}
}
此方法將盡可能降低記憶體使用率,并盡可能高效。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/529698.html
標籤:电源外壳CSV文件-io
上一篇:Java腳本物件速記
