2012-06-06 21 views
5

मेरे पास एक 1.3 जीबी पाठ फ़ाइल है जिसे मुझे PHP में कुछ जानकारी निकालने की आवश्यकता है। मैंने इसका शोध किया है और मुझे जो करने की ज़रूरत है, उसे करने के कुछ अलग-अलग तरीकों से आ गया है, लेकिन जैसा कि हमेशा थोड़ा सा स्पष्टीकरण के बाद होता है कि कौन सी विधि सबसे अच्छी होगी या यदि कोई बेहतर बेहतर है तो मुझे पता नहीं है?PHP का उपयोग कर एक 1.3 जीबी पाठ फ़ाइल से पाठ निकालने का सबसे अच्छा तरीका?

टेक्स्ट फ़ाइल में मुझे जो जानकारी चाहिए वह केवल प्रत्येक पंक्ति के पहले 40 वर्ण हैं, और फ़ाइल में लगभग 17 मिलियन लाइनें हैं। प्रत्येक पंक्ति से 40 वर्ण डेटाबेस में डाले जाएंगे।

मेरे पास विधियां नीचे हैं;

// REMOVE TIME LIMIT 
set_time_limit(0); 
// REMOVE MEMORY LIMIT 
ini_set('memory_limit', '-1'); 
// OPEN FILE 
$handle = @fopen('C:\Users\Carl\Downloads\test.txt', 'r'); 
if($handle) { 
    while(($buffer = fgets($handle)) !== false) { 
     $insert[] = substr($buffer, 0, 40); 
    } 
    if(!feof($handle)) { 
     // END OF FILE 
    } 
    fclose($handle); 
} 

ऊपर एक समय में प्रत्येक पंक्ति पढ़ सकते हैं और डेटा प्राप्त कर रहा है, मैं सभी डेटाबेस आवेषण लिया है, एक सौदे में एक बार में 50 आवेषण कर दस बार से अधिक।

अगली विधि वास्तव में ऊपर की तरह ही है लेकिन file() को डेटा प्राप्त करने के लिए foreach करने से पहले किसी सरणी में सभी लाइनों को स्टोर करने के लिए कॉल करना है? मुझे इस विधि के बारे में निश्चित नहीं है हालांकि सरणी के पास अनिवार्य रूप से 17 मिलियन से अधिक मूल्य होंगे।

एक और तरीका फ़ाइल का केवल एक हिस्सा निकालना होगा, फ़ाइल को अप्रयुक्त डेटा के साथ फिर से लिखना होगा, और उस भाग के बाद header कॉल का उपयोग करके स्क्रिप्ट को याद किया जाएगा?

यह सबसे तेज़ और कुशल तरीके से करने के मामले में सबसे अच्छा तरीका क्या होगा? या क्या इस दृष्टिकोण के लिए एक बेहतर तरीका है जिसके बारे में मैंने सोचा है?

इसके अलावा मैं इस स्क्रिप्ट का उपयोग वैंप के साथ करने की योजना बना रहा हूं, लेकिन इसे ब्राउज़र में चलाने के दौरान परीक्षण समय के दौरान टाइमआउट के साथ समस्याएं उत्पन्न हुई हैं। क्या कोई तरीका है कि मैं स्क्रिप्ट को बिना पहुंच के चलाने के लिए निष्पादित कर सकता हूं एक ब्राउज़र के माध्यम से पेज?

+0

अंतिम बिंदु के लिए, 'php path/to/script.php' स्क्रिप्ट निष्पादित करेगा। – sarnold

+0

@ कर्नाल्ड क्या मैं कमांड लाइन से ऐसा करता हूं? धन्यवाद – Griff

+1

हाँ, कमांड लाइन से। यदि आप स्क्रिप्ट की पहली पंक्ति पर '#!/Path/to/php' जोड़कर अक्सर इसे निष्पादित करना चाहते हैं तो आप इसे निष्पादन योग्य स्क्रिप्ट फ़ाइल भी बना सकते हैं और फिर' chmod 755 पथ/to/script' या 'chmod' चला रहे हैं 500' या आप जो भी उचित अनुमति चाहते हैं। – sarnold

उत्तर

5

आपके पास अब तक अच्छा है, "फ़ाइल()" फ़ंक्शन का उपयोग न करें क्योंकि यह संभवत: राम उपयोग सीमा को हिट करेगा और आपकी स्क्रिप्ट को समाप्त कर देगा।

मैं सामान को "डालने []" सरणी में भी जमा नहीं करता, क्योंकि यह रैम को भी बर्बाद कर देगा। यदि आप कर सकते हैं, तुरंत डेटाबेस में डालें।

बीटीडब्ल्यू, "कट" नामक एक अच्छा टूल है जिसे आप फ़ाइल को संसाधित करने के लिए उपयोग कर सकते हैं।

cut -c1-40 file.txt 

आप डेटाबेस में सम्मिलित कुछ PHP स्क्रिप्ट पर कट का स्टडआउट भी रीडायरेक्ट कर सकते हैं।

cut -c1-40 file.txt | php -f inserter.php 

inserter.php तब php: // stdin से लाइनें पढ़ सकता है और डीबी में डाला जा सकता है।

"कट" सभी लिनक्स पर उपलब्ध एक मानक उपकरण है, यदि आप विंडोज का उपयोग करते हैं तो आप इसे मिनजीडब्लू खोल के साथ प्राप्त कर सकते हैं, या msystools के हिस्से के रूप में (यदि आप गिट का उपयोग करते हैं) या gnuWin32 का उपयोग कर देशी Win32 ऐप इंस्टॉल कर सकते हैं।

+0

क्या यह MySQL को संभालने के लिए बहुत अधिक नहीं होगा? एक बार में एक बार 17 मिलियन बार या 50 डालें? 50 डालने के बाद सरणी रीसेट हो जाती है। – Griff

+0

@ ग्रिफ, यह PHP की सरणी पहुंच बनाम MySQL डालने की गति है। यह तेज़ हो सकता है, लेकिन यह धीमा भी हो सकता है। जांचने का एकमात्र तरीका बेंचमार्क होगा। इसके अलावा, केवल इनपुट पैरामीटर के साथ तैयार INSERT कथन का उपयोग करने से मदद मिल सकती है। –

+0

इस जानकारी के लिए धन्यवाद। इसे तुरंत काम करने के लिए मिल जाएगा और आपको बताएगा कि मैं कैसे प्राप्त करता हूं :) – Griff

2

आप PHP में ऐसा क्यों कर रहे हैं जब आपके आरडीबीएमएस में निश्चित रूप से थोक आयात कार्यक्षमता है? MySQL, उदाहरण के लिए, LOAD DATA INFILE है:

LOAD DATA INFILE 'data.txt' 
INTO TABLE `some_table` 
    FIELDS TERMINATED BY '' 
    LINES TERMINATED BY '\n'; 
    (@line) 
SET `some_column` = LEFT(@line, 40); 

एक प्रश्न।

MySQL में mysqlimport उपयोगिता भी है जो कमांड लाइन से इस कार्यक्षमता को लपेटती है।

+0

मेरा साझा होस्ट मुझे 'INFILE' का उपयोग करने की अनुमति नहीं देता है, यह मेरी पहली पसंद थी। – Griff

1

उपरोक्त में से कोई भी नहीं। fgets() का उपयोग करने में समस्या यह है कि आप अपेक्षा करते हैं कि यह काम नहीं करता है। जब अधिकतम वर्ण प्राप्त होते हैं, तो अगली कॉल fgets() उसी पंक्ति पर जारी रहेगी। आपने file() का उपयोग कर समस्या को सही ढंग से पहचाना है। तीसरी विधि एक दिलचस्प विचार है, और आप इसे अन्य समाधानों के साथ भी खींच सकते हैं।

ने कहा, fgets() का उपयोग करने का आपका पहला विचार बहुत करीब है, हालांकि हमें इसके व्यवहार को थोड़ा संशोधित करने की आवश्यकता है। यहाँ एक अनुकूलित संस्करण है कि आपकी अपेक्षानुसार काम करता रहेगा:

function fgetl($fp, $len) { 
    $l = 0; 
    $buffer = ''; 
    while (false !== ($c = fgetc($fp)) && PHP_EOL !== $c) { 
     if ($l < $len) 
      $buffer .= $c; 
     ++$l; 
    } 
    if (0 === $l && false === $c) { 
     return false; 
    } 
    return $buffer; 
} 

डालने आपरेशन तुरंत निष्पादित या आप स्मृति बर्बाद होगा। सुनिश्चित करें कि आप कई पंक्तियों को सम्मिलित करने के लिए prepared statements का उपयोग कर रहे हैं; यह निष्पादन समय को काफी हद तक कम करेगा। जब आप केवल डेटा जमा कर सकते हैं तो आप प्रत्येक सम्मिलन पर पूर्ण क्वेरी सबमिट नहीं करना चाहते हैं।

+0

क्या यह अभी भी PHP 4.3.0 के बाद से एक मुद्दा है? साथ ही, 76 गुना अधिक फ़ंक्शन कॉल के साथ गति कैसे होगी? – Wiseguy

+0

मेरा मानना ​​है कि यह fgets() के अपेक्षित व्यवहार है। अगर आप तैयार कथन (http://php.net/manual/en/pdo.prepared-statements.php) – siimsoni

+0

@KSiimson का उपयोग कर रहे हैं तो गति एक मुद्दा नहीं होना चाहिए, मैं 'पीडीओ' तैयार कथन का उपयोग कर रहा हूं, @Wiseguy यह है क्या मैंने सोचा था कि 'लंबाई' विशेषता को कम करने के रूप में मैं चाहता था? – Griff

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

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