xin/excel

基于OpenSpout封装的轻量级高性能表格处理类库,仅占用3M内存,即可轻松实现上百万行数据的高效导入与导出。

v2.0.0 2025-01-21 15:43 UTC

This package is auto-updated.

Last update: 2025-01-22 01:59:57 UTC


README

介绍

基于OpenSpout封装的轻量级高性能表格处理类库,仅占用3M内存,即可轻松实现上百万行数据的高效导入与导出。

你还在为 PhpSpreadsheet 封装的类库占用内存过大,无法满足业务需求时,而苦恼吗? 那么,Xin-Excel 就是你的救星,它基于OpenSpout封装的轻量级高性能表格处理类库,仅占用3M内存,即可轻松实现上百万行数据的高效导入与导出。 从此你就可以轻松实现Excel表格数据的导出与导入,轻松解决Excel表格数据导出与导入的问题,专注于业务逻辑,不再为表格数据导出与导入而烦恼。

安装教程

composer require xin/excel

使用说明

<?php

use Xin\Excel\Column;
use Xin\Excel\Dataset;
use Xin\Excel\Export;
use Xin\Excel\Import;

require __DIR__ . '/vendor/autoload.php';

echo "初始化内存: " . (memory_get_usage() / 1024 / 1024) . " MB\n";

$excelFilepath = 'aa.xlsx';

//======================数据导出====================================
$dataset = new Dataset(new MakeBigData(), [
	Column::integer('id', 'ID'),
	Column::title('goods_title', '商品名称'),
	Column::integer('goods_num', '数量')->setWidth(10),
	Column::price('goods_price', '单价'),
	Column::RMB('total_price', '合计'),
	Column::custom(function ($row) {
		return "{$row['master_order']['user_nickname']}(用户ID:{$row['master_order']['user_id']})";
	}, '买家信息')->setWidth(20),
	Column::create('master_order.receiver_name', '收货人姓名')->setWidth(15),
	Column::phone('master_order.receiver_phone', '收货人手机号'),
	Column::custom(function ($row) {
		return "{$row['master_order']['receiver_province']}{$row['master_order']['receiver_city']}{$row['master_order']['receiver_city']}{$row['master_order']['receiver_address']}";
	}, '收货人地址'),
	Column::create('master_order.pay_type_text', '支付方式')->setWidth(10),
	Column::create('master_order.order_no', '订单编号'),
	Column::create('master_order.order_status_text', '订单状态'),
	Column::datetime('create_time', '下单时间'),
], '订单数据');

// 快速导出数据
Export::data(new MakeBigData(), $dataset->columns(), $excelFilepath, '订单数据');

// 快速导出多个数据源
$dataset2 = clone $dataset;
$dataset2->setTitle('订单数据2');
Export::make([$dataset])->addDataset($dataset2)->save($excelFilepath);

//======================数据导入====================================

// 列映射,支持索引和首行标题两种方式进行映射
$columnsMapping = [
	'id' => 'ID',
	'goods_time' => 1,
	'create_time' => '下单时间',
];

// 加载单个工作表
$data = Import::load(
	$excelFilepath, // 加载的文件
	$columnsMapping, // 列的映射关系
	0, // 读取的起始工作表索引
	[
		'max_count' => 10,
	], // 读取的参数
);
var_dump($data);

// 加载多个工作表
$data = Import::loadMultiple(
	$excelFilepath, // 加载的文件
	[
		$columnsMapping,
		$columnsMapping,
	],// 每个工作表列的映射关系
	[0, 2], // 要读取的工作表索引或名称
	[
		0 => [
			'max_count' => 100,
		],
	],// 读取的参数
);
var_dump($data);

// 遍历工作表数据
Import::make($excelFilepath)->each(
	0,
	function ($row) {
		var_dump($row);
	},
	$columnsMapping,
	[
		'max_count' => 100,
	]
);

Import::make($excelFilepath)->chunk(
	0,
	function ($rows) {
		var_dump($rows);
	},
	$columnsMapping,
	10,
	[
		'max_count' => 100,
	]
);

// 遍历所有工作表数据
Import::make($excelFilepath)->eachAll(
	function ($row, $count) {
		var_dump($row, $count);
		return $count < 50;
	},
	[$columnsMapping],
	[],
	[
		[Import::OPTION_MAX_COUNT => 100],
	]
);

// 使用分块遍历所有工作表数据
Import::make($excelFilepath)->chunkAll(
	function ($row) {
		var_dump($row);
	},
	[$columnsMapping],
	[],
	1000,
	[
		[Import::OPTION_MAX_COUNT => 1000],
	]
);

echo "处理后内存: " . (memory_get_usage() / 1024 / 1024) . " MB\n";
echo "内存峰值: " . (memory_get_peak_usage() / 1024 / 1024) . " MB\n";

class MakeBigData implements \Iterator
{
	/**
	 * @var int
	 */
	protected $index = 0;

	/**
	 * @var int
	 */
	protected $max = 10000;

	const content = <<<TEXT
《追日者与移山人》
在古老的华夏大地上,有两个相邻的部落。一个部落居住在巍峨的太行山脚下,另一个部落则生活在广袤的平原上。太行山部落的首领是一位名叫愚公的长者,而平原部落的首领则是一位名叫追日的勇士。
愚公年事已高,但精神矍铄。他所在的部落被太行山和王屋山阻隔,交通不便,生活困苦。愚公深知,这两座大山是部落发展的最大障碍。于是,他召集族人,提出了一个大胆的计划——移山。族人们虽然对愚公的计划感到震惊,但都被他的决心所打动,纷纷响应。他们用简陋的工具,开始挖掘山石,将土石运往渤海之滨。尽管困难重重,但愚公坚信,只要子孙后代坚持不懈,终有一天会移走这两座大山。
与此同时,平原部落的追日是一位力大无穷的勇士。他的部落曾因十个太阳同时出现而陷入灾难,庄稼枯萎,土地干裂,百姓流离失所。后来,追日的祖先后羿射落九个太阳,拯救了部落。追日从小就听着后羿的故事长大,他渴望像祖先一样,为部落做出伟大的贡献。
有一天,追日得知愚公移山的壮举,深受感动。他决定前往太行山,帮助愚公的部落。当他来到愚公的部落时,看到愚公和族人们正在辛勤地劳作,尽管疲惫不堪,但无人退缩。追日被他们的精神所打动,决定加入他们。
追日的加入为移山的工程带来了巨大的帮助。他力大无穷,能轻松地举起巨石,还能用神力驱散山间的迷雾。在他的帮助下,工程进展得更快了。然而,移山并非易事,愚公的部落面临着诸多困难。智叟曾嘲笑愚公不自量力,但愚公毫不理会,依然坚持自己的信念。
随着时间的推移,愚公和追日的友谊也日益深厚。他们互相鼓励,共同面对困难。愚公告诉追日,移山的意义不仅在于改变地理环境,更在于传承一种不屈不挠的精神。追日则用他的勇气和力量,激励着族人们继续前行。
终于,在愚公和追日的共同努力下,太行山和王屋山被逐渐移平。虽然工程尚未完全结束,但道路已不再阻塞,部落的生活也逐渐改善。愚公的子孙们继承了他的遗志,继续挖掘,而追日也成为了部落的英雄。
故事传遍了大地,人们被愚公的坚持和追日的勇气所感动。他们明白,无论面对多么巨大的困难,只要心中有信念,坚持不懈,就一定能创造出奇迹。正如夸父追日时所展现的勇气和决心,虽然他最终倒在了追日的途中,但他留下的精神却激励了后人。
TEXT;

	/**
	 * @param int $max
	 */
	public function __construct(int $max = 10000)
	{
		$this->max = $max;
	}


	public function current(): mixed
	{
		return [
			'id' => $this->index + 1,
			'goods_title' => '商品名称',
			'goods_num' => random_int(0, 9999),
			'content' => self::content,
			'goods_price' => floatval(random_int(0, 99999) . "." . random_int(0, 99)),
			'create_time' => date('Y-m-d H:i:s'),
			'master_order' => [
				'user_id' => '1',
				'user_nickname' => 'xxxx',
				'receiver_phone' => '13653975075',
				'receiver_province' => '',
				'receiver_city' => '',
				'receiver_address' => '',
			],
		];
	}

	public function next(): void
	{
		$this->index++;
	}

	public function key(): mixed
	{
		return $this->index;
	}

	public function valid(): bool
	{
		return $this->index < $this->max;
	}

	public function rewind(): void
	{
		$this->index = 0;
	}
}