【问题标题】:skip n rows of csv file in php在php中跳过n行csv文件
【发布时间】:2016-05-25 06:18:06
【问题描述】:

我有一个 csv 文件,它有大约 500000 行。我需要做的是在第一个循环中获取前 100 行并操作这些行(例如,将前 100 个 ID 发送到 API 并保存响应)。在第二个循环中,跳过前 100 行(已经使用)并再使用 100 行并将请求发送到 Web 服务。同样,在第三个循环中,跳过前 200 行并获取另外 100 行并将请求发送到 Web 服务等等......

我可以用下面的代码把每一行都取一个。 (经过测试:效果很好)

if (($handle = fopen($filename, "r")) !== FALSE) {
    $id   = 1;
    $line = fgetcsv($handle); //skip first row

    //fetch data from each row
    while (($data = fgetcsv($handle, ",")) !== FALSE) {
        $hotel_id   = $data[0];
        //call service to request to web service
        $hotelDetailRequest = (new \Services\Hotel\Hotel)->getHotelStaticData($hotel_id);
        //do stuff to response
    }
}

同样,我可以跳过一些初始行,就像我跳过第一行添加一样

$line = fgetcsv($handle);
$line = fgetcsv($handle);
$line = fgetcsv($handle);

但是,如上所述,这不是我的预期结果。我正在使用 PHP(Laravel)。我用谷歌搜索,但找不到任何符合我标准的合适人选。有没有人遇到同样的问题?

任何帮助将不胜感激。谢谢你

【问题讨论】:

  • 为什么需要这样做?您是否关心发送请求的频率,还是与内存相关的性能问题?您能否详细说明为什么需要这样做,以便我们更好地了解潜在问题并提供解决方案。
  • 是的,我关心发送请求的频率。所以,我在午夜之后和早上之前运行查询。我实际上正在将静态数据保存到我的数据库中,正如我正在做的 Web 服务中所记录的那样。

标签: php csv rows skip


【解决方案1】:

这里有一个解决方案:

<?php
$filename = "the_data.csv";
$chunk_size = 200;

// parse csv file into an array
$csv_data = array_map('str_getcsv', file($filename));

// split data array into chunks
$chunked_data = array_chunk($csv_data, $chunk_size);

foreach($chunked_data as $chunk){

    // here you have $chunk_size row data
    // iterate in chunk
    foreach($chunk as $row ){
        $hotel_id   = $row[0];

        // send request to web service
        // do stuff to response
    }

    sleep(1);
}
?>

【讨论】:

  • 代码无法在此行之后运行:$csv_data = array_map('str_getcsv', file($filename));
  • 上面写着:The mydomain.loc page isn’t working mydomain.loc is currently unable to handle this request. HTTP ERROR 500.
  • 你最好在命令行 php.ini 中运行这段代码。在 Web 服务器中运行这种类型的脚本效率很低。
【解决方案2】:

您可以将SplFileObject-&gt;seek($start) 结合使用。我们可以参考您在普通 MySQL 数据库中使用的limit/offset 关系;这是一个例子:

$file = SplFileObject("myfile.csv");

$rules = DB::query("select * from file_rules where id = 1");

if ($rules->limit) {
    $file->seek($rules->offset);
}

此时,您可以执行一个简单的循环并将索引计数与您的偏移值进行比较。

foreach ($file as $index => $row ) {
    if ($file->valid() && $index <= $rules->limit ) {
        //perform your calls to do your API request
    }
}

完成后,只需更新您的数据库记录:

DB::query('update file_rules set offset='.$rules->offset+$rules->limit.' where id =1');

这就是它的要点。用您自己的替换我的数据库伪代码。这将允许您将其作为 CRON 执行并使用数据库作为交互点来获取您的 limit/offset 并使用 seek 将其应用于您的循环以进一步节省内存。

【讨论】:

  • 我不明白你到底在做什么@Ohgodwhy。
  • 能否解释一下对 laravel 的引用。
  • @vijayrana 你的意思是DB::query?我不确定你在寻找什么特异性。Laravel 是一个位于 PHP 之上的包装器,因此不会干扰基本的 PHP。
  • 我设法使用其他方法。我将 csv 的数据插入数据库并取 n 行,如TableName::all()-&gt;take(100)-&gt;skip(100)-&gt;get()
  • @vijayrana 那么这并不能解决问题。我建议标记答案或删除它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 2016-05-21
  • 2012-06-09
  • 2018-06-12
  • 2020-12-15
相关资源
最近更新 更多