对于如何使用Powershell将多个CSV文件合并为一个文件的问题有一些很好的回答,将标题行放在除this thread的第一个文件之外的所有文件上。
在大多数情况下,Kemiller2002发布的答案对我来说效果很好,但是当输出文件超过2GB时,我开始出现内存异常错误。抛出以下错误消息...
Exception of type 'System.OutOfMemoryException' was thrown.
At xxx.ps1:9 char:20
+ $false {$lines | Select -Skip 1}
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], OutOfMemoryException
+ FullyQualifiedErrorId : System.OutOfMemoryException
这是使用Powershell 5.1。它似乎不是MaxMemoryPerShellMB(报告为2147483647)的问题,它似乎也不是实际系统内存的问题 - 我上次运行时有33GB的可用内存(总共64GB) )离开了。
现在脚本一直在运行,并且添加到文件中(我的一个最终文件大小约为7GB),但是当我看到它时,我无法确定它是否捕获了所有文件中的每一行错误弹出。
有什么建议吗?
修改
我添加了一些输出,因此我可以看到错误发生的位置。我附加了11个文件,大小从350 MB到1GB不等......这两个大约1GB的文件会导致错误。其中一个报告的长度为909,050,983,另一个报告的长度为973,429,260。
答案 0 :(得分:1)
我没有大文件来测试它,但是使用.net方法可能是一种替代方法,因为你可以一次只处理1行而不是将整个内容加载到内存中。
$filepath = "c:\temp"
$outputfile = "c:\temp\output\result.csv"
$encoding = [System.Text.Encoding]::UTF8
$files = Get-ChildItem -Path $filePath -Filter *.csv
$w = New-Object System.IO.StreamWriter($outputfile, $true, $encoding)
$skiprow = $false
foreach ($file in $files)
{
$r = New-Object System.IO.StreamReader($file.fullname, $encoding)
while (($line = $r.ReadLine()) -ne $null)
{
if (!$skiprow)
{
$w.WriteLine($line)
}
$skiprow = $false
}
$r.Close()
$r.Dispose()
$skiprow = $true
}
$w.close()
$w.Dispose()
答案 1 :(得分:0)
这简直是有些人使用这种方法进行此操作的方式...
Get-Content $SrcFile1, $SrcFile2 | Set-Content $DstFile
不要那样做!它非常缓慢,并且总是会导致内存异常错误。而是使用命令处理器中的旧文件副本,例如...
cmd /c "copy $($SrcFile1) + $($SrcFile2) $($DstFile)"
答案 2 :(得分:0)
从 Bob 提出的伟大观点演变而来的完整答案
<###########################
user config section
###########################>
# location of files to concatenate
$sourcefolder = "P:\DWH\ntm_v1\uncompressed"
# source file extension
$ext = "*.csv"
# output folder (best to have new folder for safety)
$outfolder = $sourcefolder + "\..\concatenated"
#output file name
$outfilename = "concat.txt"
<###########################
do work
###########################>
# build full path to out file
$concatfile = $outfolder + "\" + $outfilename
#create output folder
md -Force $outfolder
# delete output file if exists
if (Test-Path $concatfile)
{
Remove-Item -Confirm $concatfile
}
ForEach ($file in (Get-ChildItem -Path $sourcefolder -Filter $ext)) {
$param = "type $file >> $concatfile"
Write-Host "cmd /c $param"
# run concat command
cmd /c $param;
}