我正在使用Power
shell进行一些ETL工作,根据每一行的前三个字符读取压缩文本文件并将其分解出来.
如果我只是过滤输入文件,我可以将过滤的流管理到Out-File并完成.但是我需要将输出重定向到多个目的地,据我所知,这不能用一个简单的管道来完成.我已经在使用.NET Streamreader来读取压缩的输入文件了,我想知道我是否需要使用流程编写输出文件.
天真的版本看起来像这样:
- 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怪物.
有没有一个惯用的方法来处理这个有效的w / Powershell结构,还是应该转向.NET流水作者?
有可能使用的(New-Item“path”-type“file”)对象的方法吗?
编辑上下文:
我使用DotNetZip库读取ZIP文件作为流;因此是Streamerer而不是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
- }
- }
我应该可以Dispose()两个$zipfile和$reader,但这是另一个问题!
解决方法
读
至于读取文件和解析,我会用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 $_}
- }
我认为这是更好的做法
>有正则表达式的支持,你没有
必须使子串(可能
昂贵)和
>参数
文件非常方便;)
写作
至于编写输出,我会测试使用流程,但是如果添加内容的性能适合你,我会坚持下去.
添加:
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
所以区别并不重要,对我来说,正则表达式更易于阅读.