किसी स्ट्रीम के रूप में PowerShell लाइन-बाय-लाइन में किसी फ़ाइल को संसाधित करने के लिए कैसे करें


87

मैं कुछ मल्टी-गीगाबाइट टेक्स्ट फ़ाइलों के साथ काम कर रहा हूं और पॉवरशेल का उपयोग करके उन पर कुछ स्ट्रीम प्रोसेसिंग करना चाहता हूं। यह सरल सामान है, बस प्रत्येक पंक्ति को पार्स करना और कुछ डेटा बाहर निकालना, फिर इसे डेटाबेस में संग्रहीत करना।

दुर्भाग्य से, get-content | %{ whatever($_) }स्मृति में पाइप के इस स्तर पर लाइनों के पूरे सेट को रखने के लिए प्रकट होता है। यह आश्चर्यजनक रूप से धीमा है, वास्तव में यह सब पढ़ने के लिए बहुत लंबा समय ले रहा है।

तो मेरा प्रश्न दो भागों में है:

  1. मैं इसे कैसे बना सकता हूं? मैं इस उद्देश्य के लिए RAM के कई गिग्स के उपयोग से बचना चाहूंगा।
  2. मैं इसे तेजी से कैसे चला सकता हूं? PowerShell से अधिक चलने वाला get-contentएक C # स्क्रिप्ट की तुलना में 100x धीमा प्रतीत होता है।

मुझे उम्मीद है कि मैं यहाँ कुछ गूंगा कर रहा हूँ, जैसे कोई -LineBufferSizeपैरामीटर या कोई चीज़ गायब है ...


9
गति get-contentकरने के लिए, सेट करें -RedCount को 512 पर। ध्यान दें कि इस बिंदु पर, फ़ॉरच में $ _ तार का एक सरणी होगा।
कीथ हिल

1
फिर भी, मैं .NET रीडर का उपयोग करने के रोमन के सुझाव के साथ जाऊंगा - बहुत तेजी से।
कीथ हिल

जिज्ञासा से बाहर, क्या होगा अगर मुझे गति की परवाह नहीं है, लेकिन सिर्फ स्मृति? सबसे अधिक संभावना है कि मैं .NET रीडर सुझाव के साथ जाऊंगा, लेकिन मुझे यह जानने में भी दिलचस्पी है कि इसे पूरे पाइप को मेमोरी में बफ़र करने के तरीके से कैसे रखा जाए।
स्कोबी

7
बफ़रिंग को कम करने के Get-Contentलिए वैरिएबल के परिणाम को असाइन करने से बचें क्योंकि यह पूरी फ़ाइल को मेमोरी में लोड कर देगा। डिफ़ॉल्ट रूप से, एक plineline में, Get-Contentएक बार में एक फ़ाइल को संसाधित करता है। जब तक आप परिणाम जमा नहीं कर रहे हैं या एक cmdlet का उपयोग कर रहे हैं जो आंतरिक रूप से जमता है (जैसे Sort-Object और Group-Object) तो मेमोरी हिट बहुत खराब नहीं होनी चाहिए। Foreach-Object (%) प्रत्येक पंक्ति को संसाधित करने का एक सुरक्षित तरीका है, एक बार में।
कीथ हिल

2
@dwarfsoft का कोई मतलब नहीं है। -और ब्लॉक सभी प्रोसेसिंग हो जाने के बाद केवल एक बार चलता है। आप देख सकते हैं कि यदि आप उपयोग करने का प्रयास करते हैं get-content | % -End { }तो यह शिकायत करता है क्योंकि आपने एक प्रक्रिया ब्लॉक प्रदान नहीं किया है। तो यह प्रयोग नहीं किया जा सकता है, और डिफ़ॉल्ट रूप से, यह डिफ़ॉल्ट रूप से -प्रोसेसर का उपयोग करना चाहिए। और कोशिश करो 1..5 | % -process { } -end { 'q' }कि अंत ब्लॉक केवल एक बार होता है, gc | % { $_ }अगर स्क्रिप्टब्लॉक होने के लिए डिफ़ॉल्ट रूप से सामान्य काम नहीं करेगा , और ...
TessellatingHeckler

जवाबों:


92

यदि आप वास्तव में बहु-गीगाबाइट पाठ फ़ाइलों पर काम करने वाले हैं, तो पावरशेल का उपयोग न करें। यहां तक ​​कि अगर आपको इसे पढ़ने का एक तरीका मिल जाए, तो तेजी से बड़ी मात्रा में लाइनों की प्रोसेसिंग पावरशेल में धीमी हो जाएगी और आप इससे बच नहीं सकते। यहां तक ​​कि सरल लूप महंगे हैं, 10 मिलियन पुनरावृत्तियों के लिए कहें (आपके मामले में काफी वास्तविक) हमारे पास हैं:

# "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 }
        # process the line
        $line
    }
}
finally {
    $reader.Close()
}

अद्यतन २

संभवतः बेहतर / कम कोड के बारे में टिप्पणियां हैं। मूल कोड के साथ कुछ भी गलत नहीं है forऔर यह छद्म कोड नहीं है। लेकिन रीडिंग लूप का छोटा (सबसे छोटा?) प्रकार है

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

3
FYI करें, PowerShell V3 में स्क्रिप्ट संकलन स्थिति को थोड़ा सुधारता है। कंसोल पर टाइप किए गए वी 3 पर "वास्तविक नौकरी" लूप 117 सेकंड से V2 पर 62 सेकंड तक चला गया। जब मैंने लूप को एक स्क्रिप्ट में रखा और वी 3 पर स्क्रिप्ट निष्पादन को मापा, तो यह 34 सेकंड तक गिर गया।
कीथ हिल

मैंने एक स्क्रिप्ट में तीनों परीक्षण किए और ये परिणाम मिले: वी 3 बीटा: 20/27/83 सेकंड; V2: 14/21/101 ऐसा लगता है कि मेरा प्रयोग V3 परीक्षण 3 में तेज है लेकिन पहले दो में काफी धीमा है। खैर, यह बीटा है, उम्मीद है कि आरटीएम में प्रदर्शन बेहतर होगा।
रोमन कुज़मिन

क्यों लोग इस तरह एक पाश में एक ब्रेक का उपयोग करने पर जोर देते हैं। लूप का उपयोग क्यों न करें जिसकी आवश्यकता नहीं है, और बेहतर तरीके से पढ़ता है जैसे कि लूप के लिए प्रतिस्थापित करनाdo { $line = $reader.ReadLine(); $line } while ($line -neq $null)
BeowulfNode42

1
उफ़ कि यह बराबर नहीं के लिए होना चाहिए। यह विशेष रूप से करते हैं..इस तरह लूप की समस्या है कि फ़ाइल के अंत में नल को संसाधित किया जाएगा (इस मामले में आउटपुट में)। उसके आसपास भी काम करने के लिए आपfor ( $line = $reader.ReadLine(); $line -ne $null; $line = $reader.ReadLine() ) { $line }
BeowulfNode42

4
@ BeowulfNode42, हम इसे और भी छोटा कर सकते हैं while($null -ne ($line = $read.ReadLine())) {$line}:। लेकिन विषय वास्तव में ऐसी चीजों के बारे में नहीं है।
रोमन कुजमिन

51

System.IO.File.ReadLines()इस परिदृश्य के लिए एकदम सही है। यह किसी फ़ाइल की सभी पंक्तियों को लौटाता है, लेकिन आपको तुरंत उन पंक्तियों पर पुनरावृत्ति करना शुरू कर देता है, जिसका अर्थ है कि इसमें संपूर्ण सामग्री को मेमोरी में स्टोर करने की आवश्यकता नहीं है।

.NET 4.0 या उच्चतर की आवश्यकता है।

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

http://msdn.microsoft.com/en-us/library/dd383503.aspx


6
एक नोट की आवश्यकता है: .NET फ्रेमवर्क - समर्थित: 4.5, 4. इस प्रकार, यह कुछ मशीनों पर V2 या V1 में काम नहीं कर सकता है।
रोमन कुज़मिन

इसने मुझे System.IO.File दिया, जिसमें कोई त्रुटि नहीं है, लेकिन रोमन द्वारा ऊपर दिए गए कोड ने मेरे लिए काम किया
Kolob Canyon

यह वही था जो मुझे चाहिए था, और एक मौजूदा पॉवरशेल स्क्रिप्ट में सीधे ड्रॉप करना आसान था।
user1751825

5

यदि आप सीधे PowerShell का उपयोग करना चाहते हैं तो नीचे दिए गए कोड को देखें।

$content = Get-Content C:\Users\You\Documents\test.txt
foreach ($line in $content)
{
    Write-Host $line
}

16
यही कारण है कि ओपी से छुटकारा पाना चाहता था क्योंकि Get-Contentबड़ी फ़ाइलों पर बहुत धीमी गति से होता है।
रोमन कुज़मिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.