PHP: बिना मेमोरी खत्म किए गीगाबाइट फ़ाइल लाइन दर लाइन पढ़ें

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: जब सामान्य file_get_contents सर्वर को क्रैश कर देता है

\n

एक स्थिति की कल्पना करें: आप लॉग फ़ाइल पार्स कर रहे हैं, लाखों पंक्तियों वाला CSV इम्पोर्ट कर रहे हैं, या डेटाबेस डंप प्रोसेस कर रहे हैं। आप लिखते हैं $data = file_get_contents('bigfile.log'); — और आपका PHP स्क्रिप्ट Fatal error: Allowed memory size exhausted एरर के साथ क्रैश हो जाता है। परिचित लग रहा है? अगर नहीं, तो आप भाग्यशाली हैं। लेकिन देर-सबेर हर डेवलपर को इस सवाल का सामना करना पड़ता है: "बड़ी फ़ाइल को लाइन दर लाइन कैसे पढ़ें, बिना सर्वर को क्रैश किए?"

\n

Stack Overflow पर सवाल "How to read a large file line by line?" को लाखों व्यूज़ मिल चुके हैं। और यह कोई संयोग नहीं है। इस आर्टिकल में हम सिर्फ एक नहीं, बल्कि कई तरीके देखेंगे — बेसिक से लेकर एडवांस्ड तक। आप सीखेंगे कि कैसे सिर्फ कुछ मेगाबाइट RAM का उपयोग करके दसियों गीगाबाइट की फ़ाइलें पढ़ी जा सकती हैं। चलिए शुरू करते हैं!

\n\n

क्यों file_get_contents और file() बड़ी फ़ाइलों के लिए खराब हैं

\n

ऑप्टिमाइज़ेशन में जाने से पहले, समझते हैं कि स्टैंडर्ड फंक्शन क्यों उपयुक्त नहीं हैं।

\n
    \n
  • file_get_contents() — पूरी फ़ाइल को एक स्ट्रिंग में लोड करता है। अगर फ़ाइल 2 GB की है, PHP 2 GB RAM आवंटित करने की कोशिश करेगा। 128 MB memory_limit वाले होस्टिंग पर यह गारंटीड फैटल एरर है।
  • \n
  • file() — पूरी फ़ाइल पढ़ता है और उसे स्ट्रिंग्स की एक ऐरे में बदल देता है। मेमोरी खपत और भी बढ़ जाती है (ऐरे का ओवरहेड भी जोड़ें)।
  • \n
\n

नैतिकता: अगर फ़ाइल आपके memory_limit के 10-20% से बड़ी है — तो इन फंक्शन को भूल जाइए। हमें स्ट्रीमिंग अप्रोच चाहिए।

\n\n

तरीका 1: क्लासिक — fgets() और फ़ाइल डिस्क्रिप्टर

\n

सबसे बेसिक और भरोसेमंद तरीका — fopen() के ज़रिए फ़ाइल खोलें और fgets() से लाइन दर लाइन पढ़ें। यह अप्रोच PHP के इंटरनल बफर का उपयोग करता है (आमतौर पर 8 KB) और पूरी फ़ाइल को मेमोरी में लोड नहीं करता।

\n\n
<?php\n$handle = fopen('bigfile.log', 'r');\nif ($handle) {\n    while (($line = fgets($handle)) !== false) {\n        // लाइन प्रोसेस करें\n        echo $line; // या DB में लिखें, या कुछ गणना करें\n    }\n    fclose($handle);\n} else {\n    // फ़ाइल खोलने में एरर\n    echo "फ़ाइल खोलने में विफल।";\n}\n?>
\n\n

फायदे: न्यूनतम मेमोरी खपत, किसी भी PHP वर्जन पर काम करता है।

\n

नुकसान: फ़ाइल को मैन्युअली बंद करना पड़ता है, हेडर छोड़ने या लाइनों को गिनने के लिए कोई सुविधाजनक तरीका नहीं है।

\n

यह कोड किसी भी आकार की फ़ाइल को संभाल लेगा, जब तक आप लूप के अंदर सभी लाइनों को ऐरे में सेव नहीं कर रहे।

\n\n

तरीका 2: SplFileObject — ऑब्जेक्ट-ओरिएंटेड अप्रोच

\n

PHP 5.1 से, हमारे पास शानदार क्लास SplFileObject है। यह Iterator और SeekableIterator इंटरफेस को इम्प्लीमेंट करता है, जो इसे लाइन दर लाइन पढ़ने के लिए आदर्श बनाता है।

\n\n
<?php\n$file = new SplFileObject('bigfile.log');\nwhile (!$file->eof()) {\n    $line = $file->fgets();\n    // लाइन प्रोसेस करें\n    echo $line;\n}\n?>
\n\n

लेकिन एक बात ध्यान देने वाली है! SplFileObject डिफ़ॉल्ट रूप से भी लाइनों को मेमोरी में लोड कर सकता है, अगर आप foreach के अंदर current() का उपयोग करते हैं। कम मेमोरी खपत सुनिश्चित करने के लिए, ऊपर दिखाए अनुसार while लूप में fgets() का उपयोग करें।

\n\n

ऑप्टिमाइज़ेशन के लिए फ्लैग्स रीसेट करने का एडवांस्ड वर्जन:

\n\n
<?php\n$file = new SplFileObject('bigfile.log');\n$file->setFlags(SplFileObject::DROP_NEW_LINE); // लाइन से \\n हटाएं\n\nforeach ($file as $lineNum => $line) {\n    // $lineNum — लाइन नंबर (0 से शुरू)\n    echo "लाइन $lineNum: $line\\n";\n}\n?>
\n\n

महत्वपूर्ण: SplFileObject के साथ foreach का उपयोग करने पर, PHP फिर भी एक बार में एक लाइन पढ़ता है। मेमोरी पर कोई असर नहीं पड़ता। लेकिन अगर आप $file->seek(1000000) कॉल करके फ़ाइल में कूदने की कोशिश करते हैं — तो सावधान रहें: seek सभी लाइनों को पार करता है

ब्लॉग

पुस्तक अनुशंसाएँ