Laravel 11 将大型 CSV 文件导入数据库示例
本篇文章演示,如何使用 Laravel 11 导入大型 csv 格式的数据。
有时候,我们需要将大型的 CSV 文件,例如 1 GB、2 GB、4 GB 等,导入到数据库中。大文件可能会导致 Laravel 中的超时或其他问题,但我有一个完美的解决方案来将大型 CSV 文件导入到数据库中。我们将使用 Laravel 的LazyCollection、DB 类、以及 PHP 内置的 fopen() 和 fgetcsv() 函数来读取 CSV 文件,并将数据存储到数据库。
使用这种方法的主要优点是能够高效地处理非常大的文件,而不会一次性将所有数据加载到内存中,从而避免了内存溢出或脚本执行时间过长的问题。LazyCollection允许我们以惰性求值的方式遍历集合,即只在需要时才处理数据,这非常适合处理大数据集。结合fopen()
和fgetcsv()
,我们可以逐行读取CSV文件,确保即使是非常大的文件也能被平稳处理。
下面是一个简化的流程说明:
- 使用
fopen()
打开CSV文件进行读取。 - 使用
fgetcsv()
逐行读取CSV文件的内容。 - 使用LazyCollection创建一个惰性集合,使得数据可以在不占用大量内存的情况下被迭代处理。
- 跳过CSV文件的标题行(如果有的话)。
- 将每一批数据(比如每100条记录)映射成适合插入数据库的格式。
- 使用
DB::table()->insert()
方法批量插入数据到数据库中,提高效率并减少数据库交互次数。
通过这种方式,即使是处理非常大的CSV文件,也能够有效地将其内容导入到数据库中,同时保持良好的性能和资源管理。
第一步:创建项目
$ laravel new democsv
第二步:创建迁移文件
$ php artisan make:migration create_products_table
编写迁移文件
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('amount');
$table->text('description');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
};
执行迁移文件
$ php artisan migrate
第三步:创建数据填充文件
在这里,我们将创建 ProductSeeder 类并编写导入大型 csv 文件的代码。
确保您创建的文件products.csv “name”、“amount” 和 “description” 列。将该文件放在公共文件夹中。
现在,让我们使用以下命令创建 seeder 类:
$ php artisan make:seeder ProductSeeder
第四步:编写填充文件
database/seeders/ProductSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\LazyCollection;
class ProductSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// 禁用查询日志记录,以提高性能并减少内存使用
DB::disableQueryLog();
DB::table('products')->truncate();
// 使用 LazyCollection 创建一个惰性集合,以便高效处理大型 CSV 文件
LazyCollection::make(function () {
// 打开位于 public 目录下的 'products.csv' 文件进行读取
$handle = fopen(public_path('products.csv'), 'r');
// 循环遍历每一行 CSV 数据
while (($line = fgetcsv($handle, 4096)) !== false) {
// 将一行的数据转换为字符串,并用逗号连接起来
// 形式:手机, 10, 好手机
$dataString = implode(", ", $line);
// 将字符串再拆分成数组,这一步可能是多余的,因为 $line 已经是数组了
// 此外,由于原始 CSV 分隔符已被移除,这里可能会导致数据不正确
$row = explode(',', $dataString);
// 每次迭代生成一个元素,即一行数据
yield $row;
}
fclose($handle);
})
->skip(1) // 跳过第一行(通常包含表头),只处理实际的数据行
->chunk(100) // 将数据分割成每块 100 条记录的分片,以批量插入数据库,提高效率
->each(function (LazyCollection $chunk) { // 对每个分片执行操作
// 映射每一行数据到一个关联数组中,准备插入数据库
$records = $chunk->map(function ($row) {
return [
'name' => $row[0],
'amount' => $row[1],
'description' => $row[2],
];
})->toArray();
DB::table('products')->insert($records);
});
}
}
第五步:执行填充文件
$ php artisan db:seed --class=ProductSeeder
第六步:关于 csv 文件
我们需要自己创建一个 products.csv
文件并放到 public
目录下。其内容格式如下:
name | amount | description |
---|---|---|
手机 | 10 | 自己的手机 |
请登录后再评论