如何在PowerShell中逐行处理文件作为一个流

16 浏览
0 Comments

如何在PowerShell中逐行处理文件作为一个流

我正在处理一些几十GB的文本文件,并希望使用PowerShell对其进行流式处理。处理很简单,只需解析每一行并提取一些数据,然后将其存储在数据库中。\n不幸的是,get-content | %{ whatever($_) } 在管道的这个阶段似乎会将整个行集合保存在内存中。而且它的速度出奇的慢,读取所有内容需要很长时间。\n所以我的问题有两部分:\n

    \n

  1. 如何使其逐行处理流,而不将整个内容缓存到内存中?我希望避免为此目的使用几十GB的RAM。
  2. \n

  3. 如何使其运行更快?PowerShell迭代一个get-content似乎比一个C#脚本慢100倍。
  4. \n

\n我希望这里有一些我做错了的愚蠢错误,比如缺少-LineBufferSize参数之类的东西...

0
0 Comments

如何在PowerShell中逐行处理文件流的问题出现的原因是使用Get-Content命令读取大文件时非常慢。解决方法是使用流的方式逐行处理文件内容。

下面是如何使用流处理文件内容的代码示例:

$file = [System.IO.File]::OpenText("C:\Users\You\Documents\test.txt")
while($line = $file.ReadLine()){
    Write-Host $line
}
$file.Close()

这段代码使用[System.IO.File]::OpenText方法打开文件,并使用while循环逐行读取文件内容,然后使用Write-Host命令打印每一行的内容。最后通过$file.Close()方法关闭文件。

使用流的方式逐行处理文件内容可以提高处理大文件的效率,避免使用Get-Content命令读取整个文件内容造成的性能问题。

0
0 Comments

如何逐行处理 PowerShell 中的文件流程

当我们需要逐行处理一个文件时,我们可以使用 PowerShell 中的`System.IO.File.ReadLines()`方法。这个方法非常适合这种场景,它可以返回一个文件的所有行,同时让我们立即开始迭代处理每一行,这意味着它不需要将整个文件内容存储在内存中。

在使用这个方法之前,需要确保使用的是 .NET 4.0 或更高版本。

以下是一个示例代码:

foreach ($line in [System.IO.File]::ReadLines($filename)) {
    # do something with $line
}

在这个代码中,我们使用`foreach`循环来迭代处理每一行。在循环体内部,可以根据需要对每一行进行操作。

需要注意的是,这个方法的支持版本是 .NET Framework 4.5 和 4,所以在某些机器上,可能无法在较旧版本的 PowerShell(如 V2 或 V1)中使用。如果遇到`System.IO.File does not exist`错误,可以尝试使用上述代码。

这个方法非常适合于直接将其插入到现有的 PowerShell 脚本中,使用起来非常方便。

更多关于`System.IO.File.ReadLines()`方法的信息,可以参考MSDN 文档

通过以上方法,我们可以轻松地逐行处理 PowerShell 中的文件流。无论是遍历文件内容、分析数据还是进行其他操作,都可以使用这个方法来实现。希望这篇文章对你有所帮助!

0
0 Comments

如何在PowerShell中逐行处理文件的流

如果您真的要处理多GB的文本文件,那么不要使用PowerShell。即使您找到了更快的读取方法,处理大量行的速度在PowerShell中仍然会很慢,您无法避免这一点。即使是简单的循环也是昂贵的,例如对于1000万次迭代(在您的情况下非常真实),我们有:

# "empty" loop: takes 10 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) {} }
# "simple" job, just output: takes 20 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i } }
# "more real job": 107 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i.ToString() -match '1' } }

更新:如果您仍然不害怕,可以尝试使用.NET读取器:

$reader = [System.IO.File]::OpenText("my.log")
try {
    for() {
        $line = $reader.ReadLine()
        if ($line -eq $null) { break }
        # 处理行
        $line
    }
}
finally {
    $reader.Close()
}

更新2:有关可能更好/更短的代码的评论。原始代码中的for没有问题,它不是伪代码。但是读取循环的更短(最短?)变体是:

$reader = [System.IO.File]::OpenText("my.log")
while($null -ne ($line = $reader.ReadLine())) {
    $line
}

值得一提的是,PowerShell V3中的脚本编译稍微改善了情况。在V2上,“真实的工作”循环从117秒减少到了在控制台上输入V3时的62秒。当我将循环放入脚本并测量脚本执行时,在V3上降至34秒。

我将所有三个测试放入一个脚本中,并得到以下结果:V3 Beta:20/27/83秒;V2:14/21/101。从我的实验来看,V3在第三个测试中更快,但在前两个测试中相当慢。这是测试版,希望在RTM中性能会提高。

为什么人们坚持在循环中使用break。为什么不使用不需要它的循环,比如用do { $line = $reader.ReadLine(); $line } while ($line -neq $null)替换for循环。

哎呀,应该是-ne表示不相等。那个特定的do..while循环有一个问题,即文件末尾的null将被处理(在这种情况下输出)。为了解决这个问题,你可以这样做:for ( $line = $reader.ReadLine(); $line -ne $null; $line = $reader.ReadLine() ) { $line },我们可以做得更短一些:while($null -ne ($line = $read.ReadLine())) {$line}。但是,这个话题并不是真正关于这些东西的。

+1你评论的while循环片段,很容易理解,会成为一个很好的答案。然而,你实际的答案使用for(;;)让我困惑,这是伪代码还是实际的合法PowerShell语法?如果你愿意详细说明一下,非常感谢。

D,请参见更新2

啊,现在我明白了,for(;;)for()只是一个无限循环,你可以通过break语句跳出循环,就像while(1 -eq 1)一样。是的,我通常不使用这种不明确的代码,但我不讨厌那些使用它的人^^

for()表示无限循环

while($null -ne ($line = $read.ReadLine())) {$line}会在遇到文件中的空行时提前退出while循环吗?

我测试了一下,它不会。我对PowerShell(或者说.NET)的了解还不够,无法理解为什么。空行不等于null。 $null -eq ''返回false。

作为“Power”shell,确实很难在bash中用一行代码实现的事情在这里也很难实现。

0