我有一个大的csv文件,大约9 GB,在Powershell中,我需要将它拆分成10 MB的块,问题是我需要保持行的完整性,所以每个拆分的文件都在一行的末尾结束,并在下一行的开头开始。
由于文件太大,我需要一种方法来拆分它,而不是强制代码一次上传整个文档(否则会崩溃)。
我已经做了两个星期了,还没有找到一个可行的解决方案。最糟糕的是,代码要花一天多的时间才能达到它的内存断点,所以我只能每周测试、调试和重启代码几次。进展非常缓慢。
毫无疑问,我尝试过的每个代码都会触发一个与内存相关的错误,例如“Get-Content:内存不足,无法继续执行程序。”
我试过以下方法。
如果您有这些方法的工作版本的Powershell相关链接,或者您自己知道一个更好的方法,请参与进来。
我不会给你们完整的三个代码的副本,因为那会很长,但至少这样你们会知道我已经试过什么方法了,还有不断出现的内存不足的错误。
任何帮助都将不胜感激。如果我继续在这个问题上拔我的头发,我会在我的时间之前秃头!
以前的尝试(每次都运行了一天以上,然后由于内存错误而失败)
- Get-Content(我的印象是Get-Content不会尝试一次加载所有数据,因此是最佳选择。)
Get-Content $sourceAddress |
Foreach-Object{
$var1, var2, var3 ... = $_ -Split ","
# Push these variables into a new line in a csv file
# If you've reached 100,000 lines, export a split file
}
- Import-Csv(在这里,我尝试提取一系列行之间的数据)
for ($i; $i -le $MaxSplits; $i++)
{
(Import-Csv $InCsv)[$Min..$Max] |
Export-Csv -Path $outfile -NoTypeInformation
}
1.流阅读器(ChatGPT说这是最好的方法。是的,我绝望到向AI寻求编码建议)
$reader = New-Object System.IO.StreamReader($filePath)
while (!$reader.EndOfStream) {
# Loop to retrieve the specified number of lines
for ($i = 0; $i -lt $linesPerFile; $i++) {
# Read the next line from the file
# Check if the end of the file has been reached
# If not, Add the line to the lines array
}
# Write the current batch of lines to the output file
# Increment the file counter
}
同样,任何帮助都将不胜感激。
4条答案
按热度按时间bvuwiixz1#
你可以使用steppable pipeline,因为这样可以防止你在每次迭代中打开和关闭目标文件(使用
Export-Csv
),这显然是非常昂贵的:有关完整说明,请参见:Mastering the (steppable) pipeline
laawzig22#
我不介意多个人关注这段代码。我想我已经想到了所有的东西,但是不确定。这是在PS5.1中完成的,不确定它在PS7.x中如何工作。
这个函数用于保存每个数据块。决定将
$FileLines
作为参数传递而不是通过管道传递可能是个错误-我不喜欢使用[AllowEmptyString()]
。我缺乏将字符串数组传递给函数的经验。此任务的一个问题是确定源文件的编码,我找到了this,但没有在代码中使用它。我建议检查源文件以确定它使用的编码,然后在函数中设置
Get-Content
和Out-File
命令中的一个或两个的编码以匹配它。此外,我使用了一个名为HXD的十六进制文件查看器来检查输入和输出文件。我使用的文件是我的计算机上的一些随机文件,替换为您的文件的路径和名称。
Get-Content通过管道将文件的行传输到Select-Object,然后Select-Object创建
Size
和Text
属性,这些属性是$_
的成员。计算字符串大小的想法来自this answer-因为ASCII是每个字符一个字节,所以应该忠实地工作。每行的大小增加2,假设每行的结尾是CR+LF。然后,
Foreach-Object
拆分为开始代码块、处理代码块和结束代码块。在开始代码块中,注解掉当前活动的
$OutFileSize
赋值语句,并取消注解上面的行,应该会将输出文件大小设置为10 MB。进程块计算当前总大小,如果大于$OutFileSize,则将当前存储的行转储到下一个文件中,并将当前总大小设置为等于当前行的大小。
结束块在退出之前保存$LineList缓冲区中的最后一个文件块。
我在实验中使用的文件有6,658个字节:
结果文件的大小之和也是6658。
**注意:**我不期望它很快,但是如果您只需要运行一次-它可能对您有用。
jaxagkaj3#
试试这个
wnvonmuf4#
尝试将一个100MB的文件拆分成10个10MB的文件,占用大约0.5G的内存,耗时9秒。但9G可能需要14分钟。(我真实的的用了12分钟。)
制作一个真实的的9gb测试文件(7分钟):