在 PowerShell 中逐行读取文件

我想在 PowerShell 中逐行读取文件。具体来说,我希望循环遍历该文件,将每一行存储在循环中的一个变量中,并在该行上进行一些处理。

我知道巴斯的情况:

while read line do
if [[ $line =~ $regex ]]; then
# work here
fi
done < file.txt

关于 PowerShell 循环的文档不多。

534366 次浏览

关于 PowerShell 循环的文档不多。

PowerShell 中有大量关于循环的文档,您可能想查看以下帮助主题: about_Forabout_ForEachabout_Doabout_While

foreach($line in Get-Content .\file.txt) {
if($line -match $regex){
# Work here
}
}

解决问题的另一个惯用 PowerShell 解决方案是将文本文件的行通过管道传递到 ForEach-Object cmdlet:

Get-Content .\file.txt | ForEach-Object {
if($_ -match $regex){
# Work here
}
}

不需要在循环中进行正则表达式匹配,您可以通过 Where-Object管道来过滤那些您感兴趣的行:

Get-Content .\file.txt | Where-Object {$_ -match $regex} | ForEach-Object {
# Work here
}

Get-Content的性能很差; 它试图将文件一次全部读入内存。

C # (. NET)文件读取器逐行读取

最佳表现

foreach($line in [System.IO.File]::ReadLines("C:\path\to\file.txt"))
{
$line
}

或者表现稍差一点

[System.IO.File]::ReadLines("C:\path\to\file.txt") | ForEach-Object {
$_
}

foreach语句可能会略快于 ForEach-Object语句(更多信息参见下面的注释)。

无所不能的 switch在这里运行良好:

'one
two
three' > file


$regex = '^t'


switch -regex -file file {
$regex { "line is $_" }
}

产出:

line is two
line is three

逐行读取大文件

原文(1/2021) 我能够在50秒内读取一个4GB 的日志文件,具体如下。您可以使用 PowerShell 动态地将其作为 C # 程序集加载,从而使其更快。

[System.IO.StreamReader]$sr = [System.IO.File]::Open($file, [System.IO.FileMode]::Open)
while (-not $sr.EndOfStream){
$line = $sr.ReadLine()
}
$sr.Close()

增编(3/2022) 使用嵌入在 PowerShell 中的 C # 处理大型文件甚至更快,而且“陷阱”更少。

$code = @"
using System;
using System.IO;


namespace ProcessLargeFile
{
public class Program
{
static void ProcessLine(string line)
{
return;
}


public static void ProcessLogFile(string path) {
var start_time = DateTime.Now;
StreamReader sr = new StreamReader(File.Open(path, FileMode.Open));
try {
while (!sr.EndOfStream){
string line = sr.ReadLine();
ProcessLine(line);
}
} finally {
sr.Close();
}
var end_time = DateTime.Now;
var run_time = end_time - start_time;
string msg = "Completed in " + run_time.Minutes + ":" + run_time.Seconds + "." + run_time.Milliseconds;
Console.WriteLine(msg);
}


static void Main(string[] args)
{
ProcessLogFile("c:\\users\\tasaif\\fake.log");
Console.ReadLine();
}
}
}
"@
 

Add-Type -TypeDefinition $code -Language CSharp


PS C:\Users\tasaif> [ProcessLargeFile.Program]::ProcessLogFile("c:\\users\\tasaif\\fake.log")
Completed in 0:17.109

Set-Location 'C:\files'
$files = Get-ChildItem -Name -Include *.txt
foreach($file in $files){
Write-Host("Start Reading file: " + $file)
foreach($line in Get-Content $file){
Write-Host($line)
}
Write-Host("End Reading file: " + $file)
}