0

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

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

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

希望有关于此问题的最佳解决方法的建议。谢谢!

处理部分代码如下:

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;
}
4

3 回答 3

1

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

  • 你在数组中保留一条读取线吗?
  • 您是立即在文件中写入 CSV 行,还是将所有生成的行保存在一个数组中?
  • 等等

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

于 2012-05-16T09:25:10.933 回答
0

如果您在处理 200MB 文件时用完了 1024MB 内存,那么我建议您在某个地方遇到内存问题。我建议您检查您的代码以查找可能占用不再需要的资源的区域。

于 2012-05-16T09:27:02.243 回答
0

Why do you save to MySQL only in the end of process? When you parsed a line flush that to the database, so you will just use few MB for each rows.

To address the comment:

You can use INSERT DELAYED to let database manage the load, and to don't stress it too much

于 2012-05-16T09:24:51.887 回答