如何在 Laravel 中处理大型 CSV 文件

最后更新于 作者

How to process large CSV files with Laravel image

处理庞大的 CSV 文件在商业世界中很常见,特别是在你拥有大量数据需要分析、报告或移动时。如果你使用 Laravel 并且需要处理大型 CSV 文件,你已经来对地方了。我们将指导你以最平滑的方式处理此任务,而不会影响应用程序的性能。

内存和性能

首先,让我们谈谈最棘手的问题:内存和性能。处理一个巨大的 CSV 文件会占用大量内存,并可能降低应用程序的速度。当然,你可能会考虑直接增加内存限制或延长超时时间。但说实话,这就像在漏水管上贴创可贴——并非最佳解决方案。

使用 Spatie 的 Simple Excel

与其用创可贴式的解决方案,我们不如使用一个巧妙的包,叫做 Simple Excel,由 Spatie 开发。如果你点头示意,因为你期望 Spatie 有解决方案,那你并不孤单。

composer require spatie/simple-excel

假设你已经准备好 CSV 文件,我们将使用 SimpleExcelReader 加载它。最棒的是,默认情况下,它返回一个 LazyCollection——可以将其视为一种更周到的方式来处理数据,而不会耗尽服务器的内存。这意味着你可以逐段处理文件,让应用程序保持轻便。

$rows 是 Illuminate\Support\LazyCollection 的实例

Laravel 任务前来救援

现在,在我们深入代码之前,让我们设置一个 Laravel 任务来管理我们的 CSV 处理过程。

php artisan make:job ImportCsv

现在,我们的 ImportCsv 任务看起来像这样

<?php
 
namespace App\Jobs;
 
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Spatie\SimpleExcel\SimpleExcelReader;
 
class ImportCsv implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
/**
* Create a new job instance.
*/
public function __construct()
{
//
}
 
/**
* Execute the job.
*/
public function handle(): void
{
SimpleExcelReader::create(storage_path('app/public/products.csv'))
->useDelimiter(',')
->useHeaders(['ID', 'title', 'description'])
->getRows()
->chunk(5000)
->each(
// Here we have a chunk of 5000 products
);
}
}

这是我们的计划

  1. **对 CSV 进行分块**:我们将把文件分解成可管理的小块,从而获得一个可以操作的 LazyCollection
  2. **任务调度**:对于每个块,我们将发送一个任务。这样,我们就可以分批处理,这对你的服务器来说更加轻松。
  3. **数据库插入**:每个块随后将被插入数据库,非常轻松便捷。

对 CSV 进行分块

有了 LazyCollection,我们将把 CSV 分割成块。可以将其想象成把一个巨大的三明治切成一口大小的块——更容易处理。

php artisan make:job ImportProductChunk

对于 CSV 的每块,我们将创建并触发一个任务。这些任务就像勤劳的工人,每个任务都负责一块,并小心地将数据插入数据库。

<?php
 
namespace App\Jobs;
 
use App\Models\Product;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
 
class ImportProductChunk implements ShouldBeUnique, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
public $uniqueFor = 3600;
 
/**
* Create a new job instance.
*/
public function __construct(
public $chunk
) {
//
}
 
/**
* Execute the job.
*/
public function handle(): void
{
$this->chunk->each(function (array $row) {
Model::withoutTimestamps(fn () => Product::updateOrCreate([
'product_id' => $row['ID'],
'title' => $row['title'],
'description' => $row['description'],
]));
});
}
 
public function uniqueId(): string
{
return Str::uuid()->toString();
}
}

确保唯一性

要记住的一件关键的事情是在你的任务中使用 $uniqueForuniqueId。这就像给每个工人发放一个独一无二的 ID 徽章,这样你就不会出现两个人做同一份工作的情况——这对效率来说是绝对不可取的。

调度任务

回到我们的 ImportCsv 任务中,我们将在 each 方法中为每个块调度一个任务。这就像在说,“你得到一块,你也得到一块——每个人都得到一块!”

<?php
 
namespace App\Jobs;
 
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Spatie\SimpleExcel\SimpleExcelReader;
 
class ImportCsv implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
/**
* Create a new job instance.
*/
public function __construct()
{
//
}
 
/**
* Execute the job.
*/
public function handle(): void
{
SimpleExcelReader::create(storage_path('app/public/products.csv'))
->useDelimiter(',')
->useHeaders(['ID', 'title', 'description'])
->getRows()
->chunk(5000)
->each(
fn ($chunk) => ImportProductChunk::dispatch($chunk)
);
}
}

就这样!你的块将被独立处理,而不会出现任何内存问题。如果你急于完成,只需添加更多工人,就像一台运转良好的机器一样,你的数据将被更快地处理。

在 Laravel 中处理大型 CSV 文件并不需要头疼。只要使用正确的工具和方法,你就可以让应用程序保持平稳运行,同时处理所有数据。

编码愉快!

Lokman Musliu photo

Lucky Media 的创始人兼首席执行官。软件开发人员,精通 Laravel、Statamic、Next.js、React 和 Inertia。

归档于
Cube

Laravel 新闻通讯

加入 40,000 多名其他开发者,不要错过新的技巧、教程等等。

Laravel Forge logo

Laravel Forge

轻松创建和管理你的服务器,并在几秒钟内部署 Laravel 应用程序。

Laravel Forge
Tinkerwell logo

Tinkerwell

Laravel 开发人员必备的代码运行器。使用 AI、自动完成和本地和生产环境的即时反馈进行调试。

Tinkerwell
No Compromises logo

No Compromises

Joel 和 Aaron,来自 No Compromises 播客的两名经验丰富的开发者,现在可供你的 Laravel 项目聘用。⬧ 每月 7500 美元统一价格。⬧ 无需冗长的销售流程。⬧ 无需签订合同。⬧ 100% 退款保证。

No Compromises
Kirschbaum logo

Kirschbaum

提供创新和稳定性,确保你的 Web 应用程序取得成功。

Kirschbaum
Shift logo

Shift

正在运行旧版 Laravel?即时自动化的 Laravel 升级和代码现代化,让你的应用程序保持新鲜。

Shift
Bacancy logo

Bacancy

只需每月 2500 美元,即可为你的项目配备一名经验丰富的 Laravel 开发人员,拥有 4-6 年的经验。获得 160 小时的专业服务和 15 天无风险试用。立即安排通话!

Bacancy
Lucky Media logo

Lucky Media

现在就来试试 Lucky - Laravel 开发的理想选择,拥有超过十年的经验!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel 电子商务

Laravel 的电子商务。一个开源包,将现代无头电子商务功能的强大功能带入 Laravel。

Lunar: Laravel 电子商务
LaraJobs logo

LaraJobs

官方 Laravel 工作板

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS 启动套件

SaaSykit 是一个 Laravel SaaS 启动套件,包含运行现代 SaaS 所需的所有功能。支付、精美结账、管理面板、用户仪表板、身份验证、准备好的组件、统计、博客、文档等等。

SaaSykit: Laravel SaaS 启动套件
Rector logo

Rector

你的合作伙伴,实现无缝的 Laravel 升级,降低成本,加速创新,帮助企业取得成功

Rector
MongoDB logo

MongoDB

通过 MongoDB 和 Laravel 的强大集成增强你的 PHP 应用程序,让开发者轻松高效地构建应用程序。支持事务性、搜索、分析和移动用例,同时使用熟悉的 Eloquent API。了解 MongoDB 的灵活、现代数据库如何改变你的 Laravel 应用程序。

MongoDB
Maska is a Simple Zero-dependency Input Mask Library image

Maska 是一个简单的无依赖输入掩码库

阅读文章
Add Swagger UI to Your Laravel Application image

在 Laravel 应用程序中添加 Swagger UI

阅读文章
Assert the Exact JSON Structure of a Response in Laravel 11.19 image

在 Laravel 11.19 中断言响应的精确 JSON 结构

阅读文章
Build SSH Apps with PHP and Laravel Prompts image

使用 PHP 和 Laravel Prompts 构建 SSH 应用程序

阅读文章
Building fast, fuzzy site search with Laravel and Typesense image

使用 Laravel 和 Typesense 构建快速、模糊的站点搜索

阅读文章
Add Comments to your Laravel Application with the Commenter Package image

使用 Commenter 包在 Laravel 应用程序中添加评论

阅读文章