2012-08-23 21 views
14

की संख्याओं की संख्या प्राप्त करने के तरीकों में से एक प्राप्त करें। एक फ़ाइल से लाइनों की 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> 

में इस विधि, मैं इसे कैसे से लाइन नंबर मिलता है पूरी फ़ाइल पढ़ने के बिना जब मैं एक बड़े 800 एमबी पाठ फ़ाइल है हालांकि,?

उपर्युक्त विधि बहुत अधिक रैम का उपभोग करेगी जिसके परिणामस्वरूप स्क्रिप्ट को दुर्घटनाग्रस्त हो जाएगा या पूरा होने में बहुत लंबा समय लगेगा।

उत्तर

13

उपयोग 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 
+1

ऐसा नहीं है कि अपने दूसरे दृष्टिकोण पाठ के साथ ही लाइनों में गिना जाता है ओर इशारा करते हुए के लायक है। यदि खाली रेखाएं हैं, तो उनकी गणना नहीं की जाती है। – Vladislav

8

कोशिश करने के लिए पहली बात यह है 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 
+0

उपरोक्त IO.StreamReader कोड का उपयोग करके नीचे दी गई जीसी विधि का उपयोग करते समय मुझे स्मृति त्रुटियों से बाहर निकाला गया था। मैं पुष्टि कर सकता हूं कि यह बहुत कम स्मृति का उपयोग करता है (PowerShell 5.0.10514.6 का उपयोग करके) – Fares

1

यहाँ कुछ मैं स्मृति उपयोग कम की कोशिश कर रहा करने के लिए लिखा था जब बाहर पार्स करने है मेरी txt फ़ाइल में सफेद-स्थान। इसके साथ ही, स्मृति उपयोग अभी भी बहुत अधिक मिलता है लेकिन प्रक्रिया को चलाने में कम समय लगता है। बस आपको अपनी फ़ाइल को कुछ पृष्ठभूमि देने के लिए, फ़ाइल में 2 मिलियन से अधिक रिकॉर्ड थे और प्रत्येक पंक्ति के सामने और पीछे दोनों में सफेद स्थान का नेतृत्व किया था। मेरा मानना ​​है कि कुल समय 5+ मिनट स्वरूपण को बेहतर बनाने का कोई तरीका है, तो कृपया मुझे अपने विचार बताएं। धन्यवाद

$testing = 'C:\Users\something\something\test3.txt' 

$filecleanup = gci $testing 

    foreach ($file in $filecleanup) 
    { $file1 = gc $file -readcount 1000 |foreach{ $_.Trim()} 
    $file1 > $filecleanup} 
9

यहाँ एक PowerShell स्क्रिप्ट मैं एक साथ पत्थर जो किसी पाठ फ़ाइल में लाइनों की गिनती, समय और स्मृति प्रत्येक विधि के लिए आवश्यक के साथ के कुछ ही विभिन्न तरीकों को दर्शाता है है। परिणाम (नीचे) समय और स्मृति आवश्यकताओं में स्पष्ट मतभेद दिखाते हैं। मेरे परीक्षणों के लिए, ऐसा लगता है कि मीठा स्थान 100 की रीडकाउंट सेटिंग का उपयोग करके गेट-कंटेंट था। अन्य परीक्षणों में काफी समय और/या स्मृति उपयोग की आवश्यकता थी।

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 लाइनों, 308 एमबी):

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 

#$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 

यहाँ ~ 95k लाइनों, 104 एमबी युक्त पाठ फ़ाइल के लिए परिणाम हैं

4

यहां स्यूडोथिंक की पोस्ट के आधार पर एक लाइनर है। एक विशिष्ट फ़ाइल:

"the_name_of_your_file.txt" |% {$n = $_; $c = 0; Get-Content -Path $_ -ReadCount 1000 |% { $c += $_.Count }; "$n; $c"} 

वर्तमान dir में सभी फाइलें:

Get-ChildItem "." |% {$n = $_; $c = 0; Get-Content -Path $_ -ReadCount 1000 |% { $c += $_.Count }; "$n; $c"} 
+0

कृपया इसे और अधिक विस्तार से समझाएं। –

+0

ले बिल्कुल सही समाधान। –

संबंधित मुद्दे