Laravel 中将 CSV 文件作为集合读取
大型项经常需要在某个时刻从大型 CSV 文件导入数据。如果处理不当,很可能会导致内存问题。
值得庆幸的是,你可以使用 League 的 CSV 包 方便地读取 CSV 文件,并将其作为 Laravel 的集合进行迭代。尤其是使用惰性集合。通过这种方式,可以将 CSV 文件作为集合读取,而无需将整个文件加载到内存中。
首先,请使用 Composer 安装 league/csv
包。
composer require league/csv:^9.0
然后,可以使用 League\Csv\Reader
读取 CSV 文件。你可以将 CSV 文件的路径的传递给 Reader
类的构造函数中。它将返回一个 Reader
类实例。
use League\Csv\Reader;
$cities = Reader::createFromPath('path/to/cities.csv');
然后,你可以使用 setHeaderOffset()
方法设置标题偏移值为 0
。这样会把 CSV 文件的第一行设置为标题行。
$cities->setHeaderOffset(0);
接下来,可以使用 getRecords()
方法将 CSV 文件作为集合迭代。该方法返回一个可以 将 CSV 文件作为集合迭代的生成器(Generator)。
$cities->getRecords();
然后,你可以将该生成器传递给 LazyCollection::make()
方法,以创建惰性集合。这将返回一个 LazyCollection
类实例。
最后,你可以在 LazyCollection
类中可用的方法来将 CSV 文件作为集合迭代。
比如,你可以使用 groupBy()
方法,将特定的列分组,使用 map()
方法映射记录,使用 filter()
方法过滤记录,等等。
以下是前述内容的组合:
use Illuminate\Support\LazyCollection;
use League\Csv\Reader;
$cities = Reader::createFromPath('path/to/cities.csv');
$cities->setHeaderOffset(0);
$citiesCollection = LazyCollection::make(static fn () => yield from $cities->getRecords());
->groupBy('country')
->map(fn ($cities) => $cities->count())
->toArray();
如上,我们使用静态闭包创建了一个生成器,将其传递给 LazyCollection::make()
方法。这是因为 LazyCollection::make()
需要生成器作为参数。
就是这样,你可以在 Laravel 中将 CSV 文件作为一个集合读取,而无需将整个文件加载到内存中。