PowerShell에서 큰(큰) 파일의 줄 수 가져오기
파일에서 줄 수를 가져오는 방법 중 하나는 PowerShell의 다음 방법입니다.
PS C:\Users\Pranav\Desktop\PS_Test_Scripts> $a=Get-Content .\sub.ps1
PS C:\Users\Pranav\Desktop\PS_Test_Scripts> $a.count
34
PS C:\Users\Pranav\Desktop\PS_Test_Scripts>
그러나 800MB의 대용량 텍스트 파일이 있는 경우 전체 파일을 읽지 않고 어떻게 줄 번호를 가져올 수 있습니까?
위의 방법은 RAM을 너무 많이 사용하여 스크립트가 손상되거나 완료하는 데 시간이 너무 오래 걸립니다.
사용하다Get-Content -Read $nLinesAtTime
파일을 부분별로 읽는 방법:
$nlines = 0;
# Read file by 1000 lines at a time
gc $YOURFILE -read 1000 | % { $nlines += $_.Length };
[string]::Format("{0} has {1} lines", $YOURFILE, $nlines)
다음은 소규모 파일에 대한 작업 검증을 위한 간단하지만 느린 스크립트입니다.
gc $YOURFILE | Measure-Object -Line
다음은 텍스트 파일에서 줄을 세는 몇 가지 다른 방법과 각 방법에 필요한 시간 및 메모리를 보여주는 PowerShell 스크립트입니다.결과(아래)는 시간 및 메모리 요구 사항에서 명확한 차이를 보여줍니다.제가 테스트한 바로는 읽기 횟수 설정이 100인 Get-Content인 것 같습니다.다른 테스트에서는 훨씬 더 많은 시간 및/또는 메모리 사용이 필요했습니다.
#$testFile = 'C:\test_small.csv' # 245 lines, 150 KB
#$testFile = 'C:\test_medium.csv' # 95,365 lines, 104 MB
$testFile = 'C:\test_large.csv' # 285,776 lines, 308 MB
# Using ArrayList just because they are faster than Powershell arrays, for some operations with large arrays.
$results = New-Object System.Collections.ArrayList
function AddResult {
param( [string] $sMethod, [string] $iCount )
$result = New-Object -TypeName PSObject -Property @{
"Method" = $sMethod
"Count" = $iCount
"Elapsed Time" = ((Get-Date) - $dtStart)
"Memory Total" = [System.Math]::Round((GetMemoryUsage)/1mb, 1)
"Memory Delta" = [System.Math]::Round(((GetMemoryUsage) - $dMemStart)/1mb, 1)
}
[void]$results.Add($result)
Write-Output "$sMethod : $count"
[System.GC]::Collect()
}
function GetMemoryUsage {
# return ((Get-Process -Id $pid).PrivateMemorySize)
return ([System.GC]::GetTotalMemory($false))
}
# Get-Content -ReadCount 1
[System.GC]::Collect()
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = 0
Get-Content -Path $testFile -ReadCount 1 |% { $count++ }
AddResult "Get-Content -ReadCount 1" $count
# Get-Content -ReadCount 10,100,1000,0
# Note: ReadCount = 1 returns a string. Any other value returns an array of strings.
# Thus, the Count property only applies when ReadCount is not 1.
@(10,100,1000,0) |% {
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = 0
Get-Content -Path $testFile -ReadCount $_ |% { $count += $_.Count }
AddResult "Get-Content -ReadCount $_" $count
}
# Get-Content | Measure-Object
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = (Get-Content -Path $testFile -ReadCount 1 | Measure-Object -line).Lines
AddResult "Get-Content -ReadCount 1 | Measure-Object" $count
# Get-Content.Count
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = (Get-Content -Path $testFile -ReadCount 1).Count
AddResult "Get-Content.Count" $count
# StreamReader.ReadLine
$dMemStart = GetMemoryUsage
$dtStart = Get-Date
$count = 0
# Use this constructor to avoid file access errors, like Get-Content does.
$stream = New-Object -TypeName System.IO.FileStream(
$testFile,
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::Read,
[System.IO.FileShare]::ReadWrite)
if ($stream) {
$reader = New-Object IO.StreamReader $stream
if ($reader) {
while(-not ($reader.EndOfStream)) { [void]$reader.ReadLine(); $count++ }
$reader.Close()
}
$stream.Close()
}
AddResult "StreamReader.ReadLine" $count
$results | Select Method, Count, "Elapsed Time", "Memory Total", "Memory Delta" | ft -auto | Write-Output
다음은 104MB의 ~95k 줄이 포함된 텍스트 파일에 대한 결과입니다.
Method Count Elapsed Time Memory Total Memory Delta
------ ----- ------------ ------------ ------------
Get-Content -ReadCount 1 95365 00:00:11.1451841 45.8 0.2
Get-Content -ReadCount 10 95365 00:00:02.9015023 47.3 1.7
Get-Content -ReadCount 100 95365 00:00:01.4522507 59.9 14.3
Get-Content -ReadCount 1000 95365 00:00:01.1539634 75.4 29.7
Get-Content -ReadCount 0 95365 00:00:01.3888746 346 300.4
Get-Content -ReadCount 1 | Measure-Object 95365 00:00:08.6867159 46.2 0.6
Get-Content.Count 95365 00:00:03.0574433 465.8 420.1
StreamReader.ReadLine 95365 00:00:02.5740262 46.2 0.6
다음은 더 큰 파일(최대 285k 줄, 308MB 포함)에 대한 결과입니다.
Method Count Elapsed Time Memory Total Memory Delta
------ ----- ------------ ------------ ------------
Get-Content -ReadCount 1 285776 00:00:36.2280995 46.3 0.8
Get-Content -ReadCount 10 285776 00:00:06.3486006 46.3 0.7
Get-Content -ReadCount 100 285776 00:00:03.1590055 55.1 9.5
Get-Content -ReadCount 1000 285776 00:00:02.8381262 88.1 42.4
Get-Content -ReadCount 0 285776 00:00:29.4240734 894.5 848.8
Get-Content -ReadCount 1 | Measure-Object 285776 00:00:32.7905971 46.5 0.9
Get-Content.Count 285776 00:00:28.4504388 1219.8 1174.2
StreamReader.ReadLine 285776 00:00:20.4495721 46 0.4
이것은 Pseudothink의 게시물을 기반으로 한 원라이너입니다.
특정 파일의 행 수:
"the_name_of_your_file.txt" |% {$n = $_; $c = 0; Get-Content -Path $_ -ReadCount 1000 |% { $c += $_.Count }; "$n; $c"}
current dir의 모든 파일(개별)
Get-ChildItem "." |% {$n = $_; $c = 0; Get-Content -Path $_ -ReadCount 1000 |% { $c += $_.Count }; "$n; $c"}
설명:
"the_name_of_your_file.txt"
-> 아무것도 하지 않고, 다음 단계의 파일 이름만 제공하며, 이중 따옴표를 붙여야 합니다.
|%
-> aliasForEach-Object는 제공된 항목(이 경우에는 하나만)에 대해 반복하고, Piped 콘텐츠를 입력으로 수락하며, 현재 항목은 다음에 저장됩니다.$_
$n = $_
-> $n 제공된 파일의 이름이 나중에 사용할 수 있도록 저장됩니다.$_
사실 이것은 필요 없을 수도 있습니다.
$c = 0
-> 초기화$c
셈해 보면
Get-Content -Path $_ -ReadCount 1000
-> 제공된 파일에서 1000줄 읽기 (스레드의 다른 답변 참조)
|%
-> 각 행에 대해 실제로 읽은 행 수를 추가합니다.$c
(1000 + 1000 + 123)
"$n; $c"
-> 파일 읽기를 마치면 파일 이름을 인쇄합니다. 행 수
Get-ChildItem "."
-> 단일 파일 이름보다 더 많은 항목을 파이프에 추가합니다.
첫 번째 시도는 스트리밍입니다.Get-Content
그리고 모든 라인을 한 번에 배열에 저장하는 대신 한 번에 하나씩 라인 카운트를 구성합니다.이렇게 하면 전체 파일이 한 번에 메모리에 저장되는 것이 아니라 현재 라인에 저장되는 등 적절한 스트리밍 동작을 제공할 수 있을 것으로 생각합니다.
$lines = 0
Get-Content .\File.txt |%{ $lines++ }
그리고 다른 대답이 시사하듯이, 다음과 같이 덧붙입니다.-ReadCount
속도를 높일 수 있습니다.
이 방법이 사용자에게 적용되지 않는 경우(너무 느리거나 메모리가 너무 많음) 바로 다음으로 이동할 수 있습니다.StreamReader
:
$count = 0
$reader = New-Object IO.StreamReader 'c:\logs\MyLog.txt'
while($reader.ReadLine() -ne $null){ $count++ }
$reader.Close() # Don't forget to do this. Ideally put this in a try/finally block to make sure it happens.
를 사용하는 또 다른 솔루션이 있습니다.NET:
[Linq.Enumerable]::Count([System.IO.File]::ReadLines("FileToCount.txt"))
그것은 매우 방해받지는 않지만, 기억하기는 매우 쉽습니다.
일부 대용량 파일(GB+)의 경우 SWITCH가 메모리에서 더 빠르고 쉬웠습니다.
참고: 아래 타이밍은 분:초입니다.테스트는 각 906자 길이의 14,564,836줄의 파일에 수행되었습니다.
1:27 SWITCH
$count = 0; switch -File $filepath { default { ++$count } }
1:39 IO.StreamReader
$reader = New-Object IO.StreamReader $filepath
while($reader.ReadLine() -ne $null){ $count++ }
1:42 Linq
$count = [Linq.Enumerable]::Count([System.IO.File]::ReadLines($filepath))
1:46 Get-Content based
$filepath |% {$file_line_count = 0; Get-Content -Path $_ -ReadCount 1000 |% { $file_line_count += $_.Count }}
더 빠른 방법이나 다른 접근 방식에 대해 최적화된 경우 공유하십시오.
여기 제가 txt 파일에서 공백을 파싱할 때 메모리 사용량을 줄이기 위해 쓴 내용이 있습니다.메모리 사용량은 여전히 높아지지만 프로세스 실행에 걸리는 시간은 줄어듭니다.
제 파일의 배경을 말씀드리자면, 이 파일은 2백만 개 이상의 레코드를 가지고 있으며 각 줄의 앞뒤에 공백이 있습니다.총 시간은 5분 이상이었던 것 같습니다.
$testing = 'C:\Users\something\something\test3.txt'
$filecleanup = Get-ChildItem $testing
foreach ($file in $filecleanup)
{
$file1 = Get-Content $file -readcount 1000 | foreach{$_.Trim()}
$file1 > $filecleanup
}
MS DOS 명령 찾기:$fileName = 'C:\dirname\filename.txt'
CMD /C ('find /v /c "" "' + $fileName + '"')
찾기 명령의 다른 변형은 문서에서 찾을 수 있습니다.
언급URL : https://stackoverflow.com/questions/12084642/powershell-get-number-of-lines-of-big-large-file
'source' 카테고리의 다른 글
PowerShell을 통해 .cmd 파일 실행 (0) | 2023.08.05 |
---|---|
오브젝티브-c/코코아 터치로 모듈로 작동하는 방법은 무엇입니까? (0) | 2023.08.05 |
Laravel 5.0 설치 방법 (0) | 2023.08.05 |
이 LEFT JOIN에서 반환되는 행 수를 하나로 제한하려면 어떻게 해야 합니까? (0) | 2023.08.05 |
라벨 모델이 저장되었는지 쿼리가 실행되었는지 확인합니다. (0) | 2023.08.05 |