एक बड़ी फ़ाइल लाइन को लाइन से कैसे पढ़ें?


469

मैं एक फ़ाइल लाइन को लाइन से पढ़ना चाहता हूं, लेकिन इसे पूरी तरह से मेमोरी में लोड किए बिना।

मेरी फ़ाइल स्मृति में खोलने के लिए बहुत बड़ी है, और यदि ऐसा करने की कोशिश की जाए तो मैं हमेशा मेमोरी त्रुटियों से बाहर निकलता हूं।

फ़ाइल का आकार 1 जीबी है।



7
आपको पैरामीटर के fgets()बिना उपयोग करना चाहिए $length
कार्लोस

26
क्या आप निम्न में से किसी पर उत्तर के रूप में चिह्नित करना चाहेंगे?
किम स्टैक

जवाबों:


684

आप fgets()फ़ाइल लाइन को लाइन से पढ़ने के लिए फ़ंक्शन का उपयोग कर सकते हैं :

$handle = fopen("inputfile.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        // process the line read.
    }

    fclose($handle);
} else {
    // error opening the file.
} 

3
यह too large to open in memoryभाग के लिए कैसे खाता है ?
Starx

64
आप पूरी फ़ाइल को मेमोरी में नहीं पढ़ रहे हैं। इसे चलाने के लिए आवश्यक अधिकतम मेमोरी इनपुट में सबसे लंबी लाइन पर निर्भर करती है।
कोडडक्ट

13
@ ब्रैंडिन - मूट - उन स्थितियों में, पूछा गया प्रश्न, जो एक फ़ाइल LINE BY LINE को पढ़ना है, जिसमें एक अच्छी तरह से परिभाषित परिणाम नहीं है।
टूलमेकर

3
@ToolmakerSteve फिर परिभाषित करें कि क्या होना चाहिए। यदि आप चाहते हैं कि आप केवल "लाइन बहुत लंबा; संदेश दे" प्रिंट कर सकते हैं। और यह एक अच्छी तरह से परिभाषित परिणाम भी है।
ब्रैंडिन

2
क्या एक रेखा में बूलियन झूठी हो सकती है? यदि ऐसा है तो यह विधि फ़ाइल के अंत तक पहुँचे बिना बंद हो जाएगी। इस URL पर उदाहरण # 1 php.net/manual/en/function.fgets.php बताता है कि कभी-कभी फ़िज़ूलखर्ची भी झूठी हो सकती है भले ही फ़ाइल का अंत अभी तक नहीं हुआ है। उस पृष्ठ पर टिप्पणी अनुभाग में लोग रिपोर्ट करते हैं कि फ़ॉइट () हमेशा सही मान नहीं लौटाता है, इसलिए लूपहल के रूप में फ़ॉफ़ का उपयोग करना सुरक्षित है।
कोझनसन

130
if ($file = fopen("file.txt", "r")) {
    while(!feof($file)) {
        $line = fgets($file);
        # do same stuff with the $line
    }
    fclose($file);
}

8
जैसा कि @ Cuse70 ने कहा कि यदि फ़ाइल मौजूद नहीं है या खुली नहीं हो सकती है तो उसके जवाब में एक अनंत लूप होगा। if($file)जबकि लूप से पहले टेस्ट
फ्रांसेस्कोएम

10
मुझे पता है कि यह पुराना है, लेकिन: (जबकि! Feof ($ फ़ाइल)) का उपयोग करने की अनुशंसा नहीं की जाती है। यहाँ एक नज़र है।
केविन वान राइकेगैम

BTW: "यदि फ़ाइल पॉइंटर में पढ़ने के लिए अधिक डेटा नहीं है, तो FALSE वापस आ जाता है।" php.net/manual/en/function.fgets.php ... बस के मामले में
हर

2
feof()अब मौजूद नहीं है?
रायन ड्यूवाल

94

आप किसी फ़ाइल के लिए ऑब्जेक्ट ओरिएंटेड इंटरफ़ेस क्लास का उपयोग कर सकते हैं - SplFileObject http://php.net/manual/en/splfileobject.fgets.php (PHP 5> = 5.1.0)

<?php

$file = new SplFileObject("file.txt");

// Loop until we reach the end of the file.
while (!$file->eof()) {
    // Echo one line from the file.
    echo $file->fgets();
}

// Unset the file to call __destruct(), closing the file handle.
$file = null;

3
बहुत क्लीनर समाधान। धन्यवाद;) ने अभी तक इस वर्ग का उपयोग नहीं किया है, यहां और अधिक दिलचस्प कार्य हैं जो यहां पता लगाने के लिए हैं: php.net/manual/en/class.splfileobject.php
Lukas Liesis

6
धन्यवाद। हां, उदाहरण के लिए आप $ फ़ाइल से पहले इस पंक्ति को जोड़ सकते हैं-> सेटफ्लैग्स (स्प्लिलेओओबजेक्ट :: DROP_NEW_LINE); एक पंक्ति के अंत में नई सूचियाँ छोड़ने के लिए।
elshnkhll

जहाँ तक मैं देख सकता हूँ कि eof()SplFileObject में कोई फंक्शन नहीं है ?
चुड 37

3
धन्यवाद! इसके अलावा, rtrim($file->fgets())यदि आप उन्हें नहीं चाहते हैं, तो प्रत्येक पंक्ति स्ट्रिंग के लिए नई अनुगामी स्ट्रिपिंग का उपयोग करें।
२०:३२ बजे


59

यदि आप एक बड़ी फ़ाइल खोल रहे हैं, तो आप संभवतः पूरी फ़ाइल को मेमोरी में लोड होने से बचाने के लिए () के साथ जेनरेटर का उपयोग करना चाहते हैं:

/**
 * @return Generator
 */
$fileData = function() {
    $file = fopen(__DIR__ . '/file.txt', 'r');

    if (!$file)
        die('file does not exist or cannot be opened');

    while (($line = fgets($file)) !== false) {
        yield $line;
    }

    fclose($file);
};

इसे इस तरह उपयोग करें:

foreach ($fileData() as $line) {
    // $line contains current line
}

इस तरह से आप फ़ॉर्चे के अंदर व्यक्तिगत फ़ाइल लाइनों को संसाधित कर सकते हैं ()।

नोट: जनरेटर की आवश्यकता है> = PHP 5.5


3
इसके बजाय एक स्वीकृत उत्तर होना चाहिए। जनरेटर के साथ इसका सौ गुना तेज।
ताची

1
और वाया अधिक स्मृति-कुशल।
नीनो acकोपैक

2
@ Nino thiskopac: क्या आप बता सकते हैं कि यह समाधान अधिक मेमोरी-कुशल क्यों है? उदाहरण के लिए, SplFileObjectदृष्टिकोण की तुलना में ।
k00ni

30

फ़ाइल को पढ़ने के लिए बफरिंग तकनीकों का उपयोग करें।

$filename = "test.txt";
$source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
while (!feof($source_file)) {
    $buffer = fread($source_file, 4096);  // use a buffer of 4KB
    $buffer = str_replace($old,$new,$buffer);
    ///
}

2
यह अधिक प्यार का हकदार है, क्योंकि यह बहुत बड़ी फाइलों के साथ काम करेगा, यहां तक ​​कि ऐसी फाइलें, जिनमें कोई गाड़ी नहीं है या बहुत लंबी लाइनें हैं ...
जिमरानी

मुझे आश्चर्य नहीं होगा अगर ओपी वास्तव में वास्तविक लाइनों के बारे में परवाह नहीं करता था और बस उदाहरण के लिए एक डाउनलोड करना चाहता था। उस स्थिति में, यह उत्तर ठीक है (और अधिकांश PHP कोडर वैसे भी क्या करेंगे)।
अल्वारो गोंजालेज

30

एक file()फ़ंक्शन है जो फ़ाइल में शामिल लाइनों की एक सरणी देता है।

foreach(file('myfile.txt') as $line) {
   echo $line. "\n";
}

28
एक जीबी फ़ाइल को सभी मेमोरी में पढ़ा जाएगा और एक जीबी सरणी से अधिक में परिवर्तित किया जाएगा ... सौभाग्य।
फ्रांसेस्कोएम

4
यह पूछे गए प्रश्न का उत्तर नहीं था, लेकिन यह अधिक सामान्य प्रश्न का उत्तर देता है जब बहुत से लोग यहां देखते हैं, इसलिए यह अभी भी उपयोगी था, धन्यवाद।
pilavdzice

2
फ़ाइल () छोटी फ़ाइलों के साथ काम करने के लिए बहुत सुविधाजनक है। खासकर जब आप अंतिम परिणाम के रूप में एक सरणी () चाहते हैं।
functionvoid

यह बड़ी फ़ाइलों के साथ एक बुरा विचार है क्योंकि पूरी फाइल एक बार में एक सरणी में पढ़ी जा रही है
फ्लैश थंडर

यह बड़ी फ़ाइलों पर बुरी तरह से टूट जाता है, इसलिए यह ठीक यही तरीका है जो काम नहीं करता है।
ftrotter


17

सभी उत्तरों में स्पष्ट उत्तर नहीं था।
PHP के पास एक साफ-सुथरी स्ट्रीमिंग सीमांकक पार्सर उपलब्ध है जो इस उद्देश्य के लिए उपलब्ध है।

$fp = fopen("/path/to/the/file", "r+");
while ($line = stream_get_line($fp, 1024 * 1024, "\n")) {
  echo $line;
}
fclose($fp);

यह ध्यान दिया जाना चाहिए कि यह कोड केवल पंक्तियों को वापस करेगा जब तक कि पहली खाली रेखा नहीं होती है। आप $ लाइन के लिए परीक्षण करने की जरूरत है == में जबकि हालत झूठी!while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false)
cebe

8

'जबकि (! Feof ... फ़ॉइट्स ...)' सामान के साथ सावधान रहें, फ़िज़ेट्स फ़ाइल के अंत तक पहुँचने के बिना हमेशा के लिए एक त्रुटि (गलत रिटर्निंग) और लूप प्राप्त कर सकते हैं। कोडडक्ट सही होने के करीब था, लेकिन जब आपका 'फ़ॉज' लूप समाप्त होता है, फ़ॉफ़ की जांच करें; यदि सच नहीं है, तो आपके पास एक त्रुटि थी।


8

यह मैं बहुत बड़ी फ़ाइल के साथ प्रबंधित करता हूं (100G तक परीक्षण किया गया)। और यह () की तुलना में तेज़ है

$block =1024*1024;//1MB or counld be any higher than HDD block_size*2
if ($fh = fopen("file.txt", "r")) { 
    $left='';
    while (!feof($fh)) {// read the file
       $temp = fread($fh, $block);  
       $fgetslines = explode("\n",$temp);
       $fgetslines[0]=$left.$fgetslines[0];
       if(!feof($fh) )$left = array_pop($lines);           
       foreach ($fgetslines as $k => $line) {
           //do smth with $line
        }
     }
}
fclose($fh);

आप यह कैसे सुनिश्चित करते हैं कि 1024 * 1024 ब्लॉक लाइन के बीच में नहीं टूटता है?
user151496

1
@ user151496 आसान !! गिनती ... १.२.३.४
उमर एल डॉन

@OmarElDon ​​का क्या मतलब है?
कोडेक्स 73

7

इस सवाल के लोकप्रिय समाधानों में से एक में नई लाइन चरित्र के साथ मुद्दे होंगे। यह एक सरल के साथ बहुत आसान तय किया जा सकता है str_replace

$handle = fopen("some_file.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        $line = str_replace("\n", "", $line);
    }
    fclose($handle);
}

6

SplFileObject बड़ी फ़ाइलों से निपटने के लिए उपयोगी है।

function parse_file($filename)
{
    try {
        $file = new SplFileObject($filename);
    } catch (LogicException $exception) {
        die('SplFileObject : '.$exception->getMessage());
    }
    while ($file->valid()) {
        $line = $file->fgets();
        //do something with $line
    }

    //don't forget to free the file handle.
    $file = null;
}

1
<?php
echo '<meta charset="utf-8">';

$k= 1;
$f= 1;
$fp = fopen("texttranslate.txt", "r");
while(!feof($fp)) {
    $contents = '';
    for($i=1;$i<=1500;$i++){
        echo $k.' -- '. fgets($fp) .'<br>';$k++;
        $contents .= fgets($fp);
    }
    echo '<hr>';
    file_put_contents('Split/new_file_'.$f.'.txt', $contents);$f++;
}
?>

-8

सरणी वापसी के साथ पढ़ने का कार्य

function read_file($filename = ''){
    $buffer = array();
    $source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
    while (!feof($source_file)) {
        $buffer[] = fread($source_file, 4096);  // use a buffer of 4KB
    }
    return $buffer;
}

4
यह मेमोरी में एक जीबी से अधिक का एकल सरणी बनाता है (इसके साथ सौभाग्य) लाइनों में भी नहीं बल्कि मनमाने ढंग से 4096 वर्ण खंडों में विभाजित है। पृथ्वी पर आप ऐसा क्यों करना चाहेंगे?
फ्रांसेस्कोएम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.