gpt4 book ai didi

powershell - 在 Powershell 中,按记录类型拆分大型文本文件的最有效方法是什么?

转载 作者:行者123 更新时间:2023-12-02 23:16:38 24 4
gpt4 key购买 nike

我正在使用 Powershell 进行一些 ETL 工作,读取压缩文本文件并根据每行的前三个字符将它们拆分出来。

如果我只是过滤输入文件,我可以将过滤后的流传输到 Out-File 并完成它。但我需要将输出重定向到多个目的地,据我所知,这不能通过简单的管道来完成。我已经在使用 .NET 流读取器来读取压缩的输入文件,并且我想知道是否还需要使用流编写器来写入输出文件。

天真的版本看起来像这样:

while (!$reader.EndOfFile) {
$line = $reader.ReadLine();
switch ($line.substring(0,3) {
"001" {Add-Content "output001.txt" $line}
"002" {Add-Content "output002.txt" $line}
"003" {Add-Content "output003.txt" $line}
}
}

这看起来像是个坏消息:每行一次查找、打开、写入和关闭文件。输入文件是 500MB 以上的巨大怪物。

有没有一种惯用的方法可以通过 Powershell 构造有效地处理这个问题,或者我应该求助于 .NET Streamwriter?

我可以使用(New-Item“path”-type“file”)对象的方法吗?

编辑上下文:

我正在使用DotNetZip将 ZIP 文件作为流读取的库;因此,streamreader 而不是 Get-Content/gc。示例代码:

[System.Reflection.Assembly]::LoadFrom("\Path\To\Ionic.Zip.dll") 
$zipfile = [Ionic.Zip.ZipFile]::Read("\Path\To\File.zip")

foreach ($entry in $zipfile) {
$reader = new-object system.io.streamreader $entry.OpenReader();
while (!$reader.EndOfFile) {
$line = $reader.ReadLine();
#do something here
}
}

我可能应该对 $zipfile 和 $reader 进行 Dispose(),但这是另一个问题了!

最佳答案

阅读

至于读取文件和解析,我会使用 switch 语句:

switch -file c:\temp\stackoverflow.testfile2.txt -regex {
"^001" {Add-Content c:\temp\stackoverflow.testfile.001.txt $_}
"^002" {Add-Content c:\temp\stackoverflow.testfile.002.txt $_}
"^003" {Add-Content c:\temp\stackoverflow.testfile.003.txt $_}
}

我认为这是更好的方法,因为

  • 有对正则表达式的支持,但你不支持必须制作子字符串(这可能很贵)和
  • 参数-file 非常方便;)

写作

至于编写输出,我将测试使用 Streamwriter,但是如果 Add-Content 的性能适合您,我会坚持使用它。

添加:Keith建议使用>>运算符,但是,它似乎很慢。除此之外,它以 Unicode 格式写入输出,这会使文件大小加倍。

看看我的测试:

[1]: (measure-command {
>> gc c:\temp\stackoverflow.testfile2.txt | %{$c = $_; switch ($_.Substring(0,3)) {
>> '001'{$c >> c:\temp\stackoverflow.testfile.001.txt} `
>> '002'{$c >> c:\temp\stackoverflow.testfile.002.txt} `
>> '003'{$c >> c:\temp\stackoverflow.testfile.003.txt}}}
>> }).TotalSeconds
>>
159,1585874
[2]: (measure-command {
>> gc c:\temp\stackoverflow.testfile2.txt | %{$c = $_; switch ($_.Substring(0,3)) {
>> '001'{$c | Add-content c:\temp\stackoverflow.testfile.001.txt} `
>> '002'{$c | Add-content c:\temp\stackoverflow.testfile.002.txt} `
>> '003'{$c | Add-content c:\temp\stackoverflow.testfile.003.txt}}}
>> }).TotalSeconds
>>
9,2696923

差异巨大

仅供比较:

[3]: (measure-command {
>> $reader = new-object io.streamreader c:\temp\stackoverflow.testfile2.txt
>> while (!$reader.EndOfStream) {
>> $line = $reader.ReadLine();
>> switch ($line.substring(0,3)) {
>> "001" {Add-Content c:\temp\stackoverflow.testfile.001.txt $line}
>> "002" {Add-Content c:\temp\stackoverflow.testfile.002.txt $line}
>> "003" {Add-Content c:\temp\stackoverflow.testfile.003.txt $line}
>> }
>> }
>> $reader.close()
>> }).TotalSeconds
>>
8,2454369
[4]: (measure-command {
>> switch -file c:\temp\stackoverflow.testfile2.txt -regex {
>> "^001" {Add-Content c:\temp\stackoverflow.testfile.001.txt $_}
>> "^002" {Add-Content c:\temp\stackoverflow.testfile.002.txt $_}
>> "^003" {Add-Content c:\temp\stackoverflow.testfile.003.txt $_}
>> }
>> }).TotalSeconds
8,6755565

补充:我对写作表现很好奇..而且我有点惊讶

[8]: (measure-command {
>> $sw1 = new-object io.streamwriter c:\temp\stackoverflow.testfile.001.txt3b
>> $sw2 = new-object io.streamwriter c:\temp\stackoverflow.testfile.002.txt3b
>> $sw3 = new-object io.streamwriter c:\temp\stackoverflow.testfile.003.txt3b
>> switch -file c:\temp\stackoverflow.testfile2.txt -regex {
>> "^001" {$sw1.WriteLine($_)}
>> "^002" {$sw2.WriteLine($_)}
>> "^003" {$sw3.WriteLine($_)}
>> }
>> $sw1.Close()
>> $sw2.Close()
>> $sw3.Close()
>>
>> }).TotalSeconds
>>
0,1062315

速度快了 80 倍。现在您必须做出决定 - 如果速度很重要,请使用 StreamWriter。如果代码清晰度很重要,请使用 Add-Content

<小时/>

子字符串与正则表达式

根据 Keith 的说法,Substring 快了 20%。一如既往,这取决于情况。然而,就我而言,结果是这样的:

[102]: (measure-command {
>> gc c:\temp\stackoverflow.testfile2.txt | %{$c = $_; switch ($_.Substring(0,3)) {
>> '001'{$c | Add-content c:\temp\stackoverflow.testfile.001.s.txt} `
>> '002'{$c | Add-content c:\temp\stackoverflow.testfile.002.s.txt} `
>> '003'{$c | Add-content c:\temp\stackoverflow.testfile.003.s.txt}}}
>> }).TotalSeconds
>>
9,0654496
[103]: (measure-command {
>> gc c:\temp\stackoverflow.testfile2.txt | %{$c = $_; switch -regex ($_) {
>> '^001'{$c | Add-content c:\temp\stackoverflow.testfile.001.r.txt} `
>> '^002'{$c | Add-content c:\temp\stackoverflow.testfile.002.r.txt} `
>> '^003'{$c | Add-content c:\temp\stackoverflow.testfile.003.r.txt}}}
>> }).TotalSeconds
>>
9,2563681

所以差异并不重要,对我来说,正则表达式更具可读性。

关于powershell - 在 Powershell 中,按记录类型拆分大型文本文件的最有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2159763/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com