В Powershell существует множество способов прочитать файлы. Можно использовать встроенные cmdlets, можно использовать функции .NET. Захотелось узнать, какие быстрее.
Тесты проводились на PowerShell 5.1. Просто чтение файлов используется редко, поэтому замерял время чтения и поиска простой строки. В качестве данных использовался файл 144 мб, файл 1Гб и папка с полными логами ТЖ, размером 14Гб. Все специально лежало на обычном HDD.
1. Get-Content
Самый очевидный способ. У данной команды есть псевдоним cat, для тех, кто привык к linux.
Небольшое отступление: В Powershell есть уже встроенные псевдонимы, поэтому такие команды как grep, cat, ls будут отлично работать и делать именно то, что вы от них ожидаете при вызове без параметров. Параметры в Powershell свои, поэтому скопировать сложный вызов один в один не получится.
Get-Content "E:\exchange\logs_analyze\full\*\*.log" |
Select-String -Pattern "CALL"
Результаты:
файл 144Мб - 12.1 сек
файл 1Гб - 92.8
папка 14Гб - 2608.5 сек
2. Get-Content -ReadCount
У данной команды есть параметр, который заставляет читать файл пачками строк, что должно быть быстрее на больших файлах.
2.1 Читаем по 1 строке
Get-Content "E:\exchange\logs_analyze\full\*\*.log" -ReadCount 1 |
Select-String -Pattern ",CALL," -SimpleMatch
Результаты:
файл 144Мб - 13.4 сек
файл 1Гб - не проверял
папка 14Гб - не проверял, очевидно будет долго
2.2 Читаем по 1000 строк.
Функция теперь выдает 1000 строк, поэтому пришлось добавить цикл обхода %{$_}, который передает дальше по одной строке.
Get-Content "E:\exchange\logs_analyze\full\*\*.log" -ReadCount 1000 | %{$_} |
Select-String -Pattern "CALL"
Результаты:
файл 144Мб - 5.8 сек
файл 1Гб - 42.5 сек
папка 14Гб - 1131.2 сек
2.3 Читаем по 1000 строк. Другой способ поиска
Сразу ищем в цикле
Get-Content "E:\exchange\logs_analyze\full\*\*.log" -ReadCount 1000 | %{$_ -match "CALL"}
Результаты:
файл 144Мб - 1.7 сек
файл 1Гб - 13.2 сек
папка 14Гб - 173.3 сек
папка 14Гб, чтение по 10000 строк - 178.4 сек
3. Select-String
У функции Select-String есть параметр в котором можно указать путь до файлов, и она сама прочитает их без использования Get-Content
Select-String -Path "E:\exchange\logs_analyze\full\*\*.log" -Pattern "CALL"
Результаты:
файл 144Мб - 1.7 сек
файл 1Гб - 13 сек
папка 14Гб - 173 сек
4. StreamReader
Читаем файлы используя .NET
$reader = [System.IO.StreamReader]::New(".\21053021.log")
while (!$reader.EndOfStream) {
$line = $reader.ReadLine()
if ($line.Contains("CALL")) {
$lines += $line
}
}
Результаты:
файл 144Мб - 2.5 сек
файл 1Гб - 20 сек
папка 14Гб - не тестировал
5. ReadAllLines
Читаем сразу все строки файла. При тестах оказалось, что этот метод есть много памяти.
$Lines = [System.IO.File]::ReadAllLines(".\21053021.log")
[Regex]::Matches($Lines, "CALL")
Результаты:
файл 144Мб - 2.8 сек
файл 1Гб - 21,5 сек
папка 14Гб - не тестировал
6. ReadLines
Get-ChildItem -Path "E:\exchange\logs_analyze\full\*\*.log" | % {
foreach($line in [System.IO.File]::ReadLines($_))
{
if ($line.Contains("CALL")) {
$line
}
}
}
Результаты:
файл 144Мб - 1.65 сек
файл 1Гб - 12.5 сек
папка 14Гб - 177 сек
Выводы
При одинаковой скорости работы способов 2.3, 3, 6, удобнее всего использовать простой Select-String.
Сравнивать по скорости с grep из linux нет никакой необходимости, тут PowerShell проигрывает без шансов.