编程

Laravel 中将 CSV 文件作为集合读取

114 2024-05-19 01:32:00

大型项经常需要在某个时刻从大型 CSV 文件导入数据。如果处理不当,很可能会导致内存问题。
值得庆幸的是,您可以使用League 的 CS V包 方便地读取 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 文件作为一个集合读取,而无需将整个文件加载到内存中。