我有一个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)。我用谷歌搜索,但找不到符合我标准的任何合适品。有没有人面临同样的问题?
任何帮助将不胜感激。谢谢
答案 0 :(得分: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);
}
?>
答案 1 :(得分:0)
您可以将SplFileObject
与->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');
这是它的主旨。用您自己的代码替换我的DB伪代码。这将允许您将其作为CRON执行,并使用数据库作为交互点来获取limit/offset
并使用seek
将其应用于循环以进一步节省内存。