繁体   English   中英

Laravel CSV导入内存不足(允许内存耗尽)

[英]Laravel CSV Import running out of memory (allowed memory exhausted)

我已经得到了我一个月包含〜6000行领取一次成员的CSV文件。

我正在(试图)遍历CSV文件,检查record已在members表中存在,如果存在,请检查record是否相同。

然后将其插入pending表(在适当的地方带有一个存在标志)。

我正在使用Laravel和League \\ CSV读取保存在我的storage文件夹中的文件:

class ImportController extends Controller
{
  public function import(Request $request) {

    $readDirectory = 'storage/csv/';
    $filename = $request->name;

    $stream = fopen($readDirectory.$filename, 'r');
    $reader = Reader::createFromStream($stream, 'r')->setHeaderOffset(0);
    $records = (new Statement())->process($reader);

    // Truncate the imported table prior to import
    Imported::truncate(); 

    foreach ($records as $record) {

        $email = $record['email'];

        $recordExists = $this->recordExists($email);

        if($recordExists) {
          // Compare the md5 of the recordArray and the memberArray and skip the record if thit's the same.
          $memberArray = $this->getmemberArray($recordExists);
          $recordArray = $this->getRecordArray($record);

          if($memberArray['hash'] === $recordArray['hash']) { continue; }

          $record['exists'] = TRUE;
          $this->write($record);

          continue;
        }


        else
        {
          $record['exists'] = FALSE;
          $this->write($record);
          Log::debug("missing: ".$record['URN']);

          continue;
        }
      };
    // End Foreach Loop

    return redirect()->route('upload.show');
  }



  public function recordExists($urn){
    $member = Member::where('email', 'LIKE', $email)->first();
    if ($member == null) { return false; }
    return $member;
  }

  public function getmemberArray($member) {
    $memberArray = [
      'email'       =>  $member->email,
      'first_name'  =>  $member->first_name,
      'last_name'   =>  $member->last_name,
      'age_years'   =>  $member->age_years,
      'gender'      =>  $member->gender,
      'address_1'   =>  $member->address_1,
      'address_2'   =>  $member->address_2,
      'address_3'   =>  $member->address_3,
      'town'        =>  $member->town,
      'county'      =>  $member->county,
      'postcode'    =>  $member->postcode,
      'sport_1'     =>  $member->sport_1,
      'sport_2'     =>  $member->sport_2,
    ];
    $memberArray['hash'] = md5(json_encode($memberArray));
    return $memberArray;
  }

  public function getRecordArray($record) {
    $recordArray = [
      'email'       =>  $record['email'], 
      'first_name'  =>  $record['first_name'], 
      'last_name'   =>  $record['last_name'], 
      'age_years'   =>  $record['age_years'], 
      'gender'      =>  $record['gender'],
      'address_1'   =>  $record['address_1'], 
      'address_2'   =>  $record['address_2'], 
      'address_3'   =>  $record['address_3'], 
      'town'        =>  $record['town'], 
      'county'      =>  $record['county'], 
      'postcode'    =>  $record['postcode'], 
      'sport_1'     =>  $record['sport_1'], 
      'sport_2'     =>  $record['sport_2'], 
    ];
    $recordArray['hash'] = md5(json_encode($recordArray));
    return $recordArray;
  }

  public function write($record) {

    $import = [];

    $import['email']      = $record['email'], 
    $import['first_name'] = $record['first_name'], 
    $import['last_name']  = $record['last_name'], 
    $import['age_years']  = $record['age_years'], 
    $import['gender']     = $record['gender'],
    $import['address_1']  = $record['address_1'], 
    $import['address_2']  = $record['address_2'], 
    $import['address_3']  = $record['address_3'], 
    $import['town']       = $record['town'], 
    $import['county']     = $record['county'], 
    $import['postcode']   = $record['postcode'], 
    $import['sport_1']    = $record['sport_1'], 
    $import['sport_2']    = $record['sport_2'], 
    $import['exists']     = $record['exists']

    DB::table('imported')->insert(
      $import
    );

    Log::debug($record['email']);

    return TRUE;
  }
}

但我不断得到:

Symfony \\ Component \\ Debug \\ Exception \\ FatalErrorException (E_UNKNOWN) Allowed memory size of 134217728 bytes exhausted (tried to allocate 181321056 bytes)

如果我在CSV中使用的行少得多,则可以使用,但这不是一种选择。

我以前使用eloquent->save()来写数据库,但是将其更改为DB::table()->insert以提高性能。

为了测试目的,我已经添加了以下内容,但仍无法解决。

set_time_limit(0);
ini_set('max_execution_time', 100000);
ini_set('memory_limit','512m');

我想念什么吗? 某处内存泄漏?

我猜想它每次都会将记录保存在内存中,所以有什么方法可以让每一行都忘记它吗?

还:有一种方法可以清除此内存,以便我可以编辑代码并重试?

即使我停止并重新运行php artisan serve它仍然保留相同的错误消息。

这里的问题是,当您执行以下操作时, League\\CSV正在将整个CSV文件读取到内存中:

$records = (new Statement())->process($reader);

您应该像这样使用Readerchunk方法来一次只读取特定数量的行:

 foreach($reader->chunk(50) as $row) { // do whatever } 

chunk方法返回一个可以迭代的生成器 您可以在文档中找到此处提到的内容

编辑:我误读了文档,并建议使用错误的方法。

基本上,您只需要遍历$reader本身:

 foreach ($reader as $row) { print_r($row); } 

另外,如果您使用的是Mac,或者您的CSV是在Mac上创建的,则需要使用以下内容才能成功读取大型CSV文件:

 if (!ini_get('auto_detect_line_endings')) { ini_set('auto_detect_line_endings', '1'); } 

请参阅文档的这一部分

我知道您正在使用php artisan serve来运行服务器。 您可以尝试部署某种形式的实际Web服务器,因为您将在生产环境中使用它。 您可以尝试Apache,在Windows和Linux的XAMPP中很容易获得。

您可以在线检查如何在操作系统上安装Apache HTTP Server或Nginx。 这些具有更好的控制和使用php默认服务器的内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM