在PHP中处理大文件

时间:2012-05-16 09:07:36

标签: php mysql unix

在php中处理非常大的文件的最佳方法是什么? 这是我目前的情景:

  1. 我从网络管理系统(NMS)中提取有关所有网络元素的所有参数的原始文件(NMS在UNIX框中运行)。
  2. 我使用PHP在我的PC盒中FTP原始文件。
  3. 我使用PHP的fget()函数逐行处理原始文件。
  4. 每行使用字符串匹配和正则表达式匹配来提取必要的数据,直到我能够用逗号分隔1行必要数据(",")。
  5. 我重复步骤4直到EOF并拥有完整的CSV文件。
  6. 然后我使用sql" LOAD DATA INFILE"
  7. 将此数据投放到我的数据库

    我现在的问题是,我有1个原始文件达到更多/更少200MB,并且有更多/更少180列数据因为这些我的PHP脚本无法完成处理整个文件,因为在处理它是耗尽所有的我在php.ini文件中分配的1024MB内存。

    希望对此问题的最佳解决方案进行推荐。谢谢!

    以下处理部分的代码:

    while( !feof($fh) ){
    set_time_limit(0);
    $l_buffer = fgets( $fh, $fsize );
    $l_LineStream = explode( ' ', trim( $l_buffer ) );
    $l_FilteredLineStream = array_filter( $l_LineStream, array( $this, 'RemoveEmptyElement' ) );
    $l_GrepMatchArray = preg_grep( '/^BSC.*_.*$/', $l_FilteredLineStream );
    if( count( $l_GrepMatchArray ) > 0 ){
        foreach( $l_GrepMatchArray as $l_BSCFound ){
            $l_BSCFound = explode( '_', $l_BSCFound );
            $l_BSCHoming = $l_BSCFound[1];
        }
    }
    $l_GrepMatchArray = preg_grep( '/^BTS-[0-9]*$/', $l_FilteredLineStream );
    if( count( $l_GrepMatchArray ) > 0 ){
        foreach( $l_GrepMatchArray as $l_BTSFound ){
            $l_CurrBTS = $l_BTSFound;
        }
    }
    /**/
    if( $l_PrevBTS != $l_CurrBTS && isset( $l_BTSArray ) && count( $l_BTSArray ) > 0 ){
        #$this->BTS_Array[] = $l_BTSArray;
        if( $l_FirstLoop == true ){
            $this->WriteDataToCSVFile( $l_BTSArray, $l_FilePath, true );
            $l_FirstLoop = false;
        }else{
            $this->WriteDataToCSVFile( $l_BTSArray, $l_FilePath );
        }
    }
    /**/
    if( count( $l_GrepMatchArray ) > 0 ){
        #var_dump( $l_FilteredLineStream );
        $l_BTSArray = $this->InstantiateEmptyBTSArray();
        #$l_BTSArray['CI'] = '';
        $l_BTSArray['BSC'] = $l_BSCHoming;
        $l_BTSArray['BCF'] = $l_FilteredLineStream[0];
        $l_BTSArray['BTS'] = $l_FilteredLineStream[3];
        $l_BTSArray['CELL NAME'] = $l_FilteredLineStream[6];
    }
    if( $l_GetPLMNNextLineData == true && isset( $l_BTSArray['PLMN'] ) ){
        $l_BTSArray['PLMN'] .= trim( $l_buffer );
        $l_GetPLMNNextLineData = false;
    }
    $l_GrepMatchArray = preg_match( '/\.\(.*$/', $l_buffer, $reg_match );
    
    if( count( $reg_match ) > 0 ){
        $l_KeyName = substr( $reg_match[0], 2, strpos( $reg_match[0], ')' ) - 2 );
        preg_match( '/[[:space:]].*|[-].*/', $reg_match[0], $param_value );
        $l_BTSArray[$l_KeyName] = trim( $param_value[0] );
        if( $l_KeyName == 'PLMN' ){
            $l_GetPLMNNextLineData = true;
        }
    }
    $l_PrevBTS = $l_CurrBTS;
    }
    

3 个答案:

答案 0 :(得分:1)

你应该检查你的脚本是否真的逐行处理大文件(一次一行)。

  • 你在数组中保留一条读线吗?
  • 您是否立即在文件中写入CSV行,或者将所有生成的行保留在数组中?

如果逐行处理文件,则不应使用1GB +内存。

答案 1 :(得分:0)

为什么只在流程结束时保存到MySQL? 解析到数据库的行刷新时,每行只使用几MB。

解决评论:

您可以使用INSERT DELAYED让数据库管理负载,并且不要过分强调

答案 2 :(得分:0)

如果你的内存不足1024MB处理一个200MB的文件,那么我建议你在某个地方有内存问题。我建议你查看你的代码,找出那些可能不再需要的资源。