从php中的csv文件读取大数据[重复]

Posted

技术标签:

【中文标题】从php中的csv文件读取大数据[重复]【英文标题】:Read large data from csv file in php [duplicate] 【发布时间】:2013-07-05 09:34:42 【问题描述】:

我正在读取 csv 并使用 mysql 检查记录是否存在于我的表中或不在 php 中。

csv 有近 25000 条记录,当我运行我的代码时,它在 2m 10s 后显示“服务不可用”错误(加载时间:2m 10s)

这里我添加了代码

// for set memory limit & execution time
ini_set('memory_limit', '512M');
ini_set('max_execution_time', '180');

//function to read csv file
function readCSV($csvFile)

    $file_handle = fopen($csvFile, 'r');
    while (!feof($file_handle) ) 

       set_time_limit(60); // you can enable this if you have lot of data

       $line_of_text[] = fgetcsv($file_handle, 1024);
   
   fclose($file_handle);
   return $line_of_text;
 

// Set path to CSV file
$csvFile = 'my_records.csv';

$csv = readCSV($csvFile);

for($i=1;$i<count($csv);$i++)

   $user_email= $csv[$i][1];

   $qry = "SELECT u.user_id, u.user_email_id FROM tbl_user as u WHERE u.user_email_id = '".$user_email."'";

   $result = @mysql_query($qry) or die("Couldn't execute query:".mysql_error().''.mysql_errno());

   $rec = @mysql_fetch_row($result);

   if($rec)
   
      echo "Record exist";
   
   else
   
      echo "Record not exist"; 
   

注意:我只想列出表中不存在的记录。

请建议我解决这个问题...

【问题讨论】:

内存限制怎么办?你检查过你的日志吗? @Robert 让我检查日志... 这里是时间日志信息:时间 - 5m 44s (onload: 5m 44s) 总内存 - 2.8 MB 增加执行时间。 哪里说服务不可用 【参考方案1】:

一般情况下,500错误会出现“Service Unavailable”错误。 我认为这是因为执行时间不足。请检查您的日志/浏览器控制台,您可能会看到 500 错误。

首先, 让 set_time_limit(60) 脱离循环。

做一些改变,比如,

    在 user_email_id 列上应用 INDEX,这样您就可以通过选择查询更快地获取行。 不要回显消息,保持输出缓冲区空闲。

我已经使用开源程序完成了这些拍摄。你可以在这里得到它http://sourceforge.net/projects/phpexcelreader/

试试这个。

【讨论】:

是的,我在控制台上看到了 500 - 内部服务器错误,我还添加了代码以增加最大执行时间 ini_set('memory_limit', '512M'); ini_set('max_execution_time', '180'); set_time_limit(60) 在 while 循环中,将其置于 readCSV() 之外【参考方案2】:

处理大文件的绝佳方法位于:https://***.com/a/5249971/797620

此方法用于http://www.cuddlycactus.com/knownpasswords/(页面已被删除)在几毫秒内搜索超过 170+ 百万个密码。

【讨论】:

第二个链接坏了,所以我们看不到这个方法是如何使用的。因此,这使得第二段毫无意义,并且答案变得非常低质量,因为它只是一个链接答案。【参考方案3】:

经过一番努力,我终于找到了一个好的解决方案,也许它也可以帮助别人。 当我尝试包含 18226 行的 2,367KB csv 文件时,不同 php 脚本花费的最少时间是 (1) 来自 php.net fgetcsv 名为 CsvImporter 的文档,以及 (2)file_get_contents => PHP Fatal error: Allowed memory exhausted

(1) 花了 0.92574405670166 (2) 取 0.12543702125549 (字符串形式) & 0.52903485298157 (拆分成数组) 注意:此计算不包括添加到mysql。

我找到的最佳解决方案是使用3.0644409656525,包括添加到数据库和一些条件检查。 处理一个 8MB 文件需要 11 秒。 解决方案是:

$csvInfo = analyse_file($file, 5);
    $lineSeperator = $csvInfo['line_ending']['value'];
    $fieldSeperator = $csvInfo['delimiter']['value'];
    $columns = getColumns($file);
    echo '<br>========Details========<br>';
    echo 'Line Sep: \t '.$lineSeperator;
    echo '<br>Field Sep:\t '.$fieldSeperator;
    echo '<br>Columns: ';print_r($columns);
    echo '<br>========Details========<br>';
    $ext = pathinfo($file, PATHINFO_EXTENSION);
    $table = str_replace(' ', '_', basename($file, "." . $ext));
    $rslt = table_insert($table, $columns);
    if($rslt)
        $query = "LOAD DATA LOCAL INFILE '".$file."' INTO TABLE $table FIELDS TERMINATED BY '$fieldSeperator' ";

        var_dump(addToDb($query, false));
    


function addToDb($query, $getRec = true)
//echo '<br>Query : '.$query;
$con = @mysql_connect('localhost', 'root', '');
@mysql_select_db('rtest', $con);
$result = mysql_query($query, $con);
if($result)
    if($getRec)
         $data = array();
        while ($row = mysql_fetch_assoc($result))  
            $data[] = $row;
        
        return $data;
    else return true;
else
    var_dump(mysql_error());
    return false;




function table_insert($table_name, $table_columns) 
    $queryString = "CREATE TABLE " . $table_name . " (";
    $columns = '';
    $values = '';

    foreach ($table_columns as $column) 
        $values .= (strtolower(str_replace(' ', '_', $column))) . " VARCHAR(2048), ";
    
    $values = substr($values, 0, strlen($values) - 2);

    $queryString .= $values . ") ";

    //// echo $queryString;

    return addToDb($queryString, false);



function getColumns($file)
    $cols = array();
    if (($handle = fopen($file, 'r')) !== FALSE)
    
        while (($row = fgetcsv($handle)) !== FALSE) 
        
           $cols = $row;
           if(count($cols)>0)
                break;
           
        
        return $cols;
    else return false;


function analyse_file($file, $capture_limit_in_kb = 10) 
// capture starting memory usage
$output['peak_mem']['start']    = memory_get_peak_usage(true);

// log the limit how much of the file was sampled (in Kb)
$output['read_kb']                 = $capture_limit_in_kb;

// read in file
$fh = fopen($file, 'r');
    $contents = fread($fh, ($capture_limit_in_kb * 1024)); // in KB
fclose($fh);

// specify allowed field delimiters
$delimiters = array(
    'comma'     => ',',
    'semicolon' => ';',
    'tab'         => "\t",
    'pipe'         => '|',
    'colon'     => ':'
);

// specify allowed line endings
$line_endings = array(
    'rn'         => "\r\n",
    'n'         => "\n",
    'r'         => "\r",
    'nr'         => "\n\r"
);

// loop and count each line ending instance
foreach ($line_endings as $key => $value) 
    $line_result[$key] = substr_count($contents, $value);


// sort by largest array value
asort($line_result);

// log to output array
$output['line_ending']['results']     = $line_result;
$output['line_ending']['count']     = end($line_result);
$output['line_ending']['key']         = key($line_result);
$output['line_ending']['value']     = $line_endings[$output['line_ending']['key']];
$lines = explode($output['line_ending']['value'], $contents);

// remove last line of array, as this maybe incomplete?
array_pop($lines);

// create a string from the legal lines
$complete_lines = implode(' ', $lines);

// log statistics to output array
$output['lines']['count']     = count($lines);
$output['lines']['length']     = strlen($complete_lines);

// loop and count each delimiter instance
foreach ($delimiters as $delimiter_key => $delimiter) 
    $delimiter_result[$delimiter_key] = substr_count($complete_lines, $delimiter);


// sort by largest array value
asort($delimiter_result);

// log statistics to output array with largest counts as the value
$output['delimiter']['results']     = $delimiter_result;
$output['delimiter']['count']         = end($delimiter_result);
$output['delimiter']['key']         = key($delimiter_result);
$output['delimiter']['value']         = $delimiters[$output['delimiter']['key']];

// capture ending memory usage
$output['peak_mem']['end'] = memory_get_peak_usage(true);
return $output;

【讨论】:

function analyse_file 取自php.net/manual/fr/function.fgetcsv.php#101238 我设法在我的定位器应用程序中使用 MySQL 加载数据方法进行 CSV 处理。 100,00 个位置在 75 秒内加载,而使用 fget_csv() 或文件分块则需要 10 小时。如果您将 CSV 直接加载到持久数据存储中,绝对值得研究。大多数 SQL 引擎都有类似的功能。谢谢拉扎!

以上是关于从php中的csv文件读取大数据[重复]的主要内容,如果未能解决你的问题,请参考以下文章

从 csv 文件中读取数据需要很长时间 [重复]

用逗号读取大的 .csv 文件 MATLAB [重复]

如何读取 CSV 文件 [重复]

在 PHP 中读取 CSV 文件返回黑色菱形问号

怎样从matlab中读取csv文件

PHP 读取和导出 CSV文件