Thinkphp 怎样导出大数据到Excel

chenvle 2024-11-26 PM 914℃ 38条

在 ThinkPHP 中导出大数据时,直接从数据库中查询所有数据并一次性导出可能会导致内存占用过高,甚至导致服务器崩溃。为了解决这个问题,可以采取分批导出队列文件流等技术来优化大数据导出过程。

1. 分批查询并导出

分批查询并导出可以有效减少内存占用,每次只从数据库中查询一部分数据,处理并写入到导出文件中。以下是一个常见的处理流程,假设要导出 CSV 文件:

示例:分批导出 CSV

use think\facade\Db;

// 设置导出文件名
$fileName = 'export_' . date('YmdHis') . '.csv';

// 打开输出缓冲区并准备写入文件
$fp = fopen('php://output', 'w');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="' . $fileName . '"');

// 设置每页大小
$pageSize = 1000;
$totalCount = Db::name('your_table')->count();
$pageCount = ceil($totalCount / $pageSize);

// 写入 CSV 表头
fputcsv($fp, ['ID', 'Name', 'Age', 'Email']);

// 分页查询并导出
for ($page = 1; $page <= $pageCount; $page++) {
    $dataList = Db::name('your_table')
        ->limit(($page - 1) * $pageSize, $pageSize)
        ->select();

    // 写入 CSV 内容
    foreach ($dataList as $row) {
        fputcsv($fp, $row);
    }

    // 释放内存
    unset($dataList);
}

// 关闭输出缓冲区
fclose($fp);
exit();

说明:

  1. 使用 fopen('php://output', 'w') 直接向浏览器输出文件内容。
  2. 使用分页查询,每次查询一部分数据并写入 CSV 文件。
  3. fputcsv 函数用于将数据写入 CSV 文件。

2. 使用队列导出

对于非常大的数据量,可能需要异步处理导出任务。可以使用队列系统,将导出任务拆分成多个小任务,后台处理完后通知用户下载。

示例:使用队列导出 CSV

  1. 定义队列任务
// app\job\ExportJob.php
namespace app\job;

use think\queue\Job;
use think\facade\Db;

class ExportJob
{
    public function fire(Job $job, $data)
    {
        $filePath = $data['file_path'];
        $fp = fopen($filePath, 'a');

        // 查询数据并写入文件
        $pageSize = 1000;
        $page = $data['page'];
        $dataList = Db::name('your_table')
            ->limit(($page - 1) * $pageSize, $pageSize)
            ->select();

        foreach ($dataList as $row) {
            fputcsv($fp, $row);
        }

        fclose($fp);
        unset($dataList);

        // 如果还有任务,继续执行
        if ($job->attempts() > 3) {
            // 任务失败处理
            $job->delete();
        } else {
            // 任务成功,删除任务
            $job->delete();
            if ($page < $data['total_pages']) {
                // 继续下一个分页任务
                $job->release();
            }
        }
    }
}
  1. 推送任务到队列
use think\Queue;

$filePath = 'export_' . date('YmdHis') . '.csv';
$totalCount = Db::name('your_table')->count();
$pageSize = 1000;
$pageCount = ceil($totalCount / $pageSize);

// 初始化 CSV 文件并写入表头
$fp = fopen($filePath, 'w');
fputcsv($fp, ['ID', 'Name', 'Age', 'Email']);
fclose($fp);

// 将任务推送到队列
for ($page = 1; $page <= $pageCount; $page++) {
    Queue::push('app\job\ExportJob', ['file_path' => $filePath, 'page' => $page, 'total_pages' => $pageCount], 'export');
}
  1. 下载导出的文件

当所有队列任务执行完毕后,用户可以下载生成的文件。你可以在控制器中提供下载链接:

public function download()
{
    $filePath = 'export_' . date('YmdHis') . '.csv';
    if (file_exists($filePath)) {
        return response()->download($filePath);
    } else {
        return "File not found";
    }
}

3. 使用临时文件分批写入

对于非常大的数据量,还可以将导出的文件分批写入多个临时文件,最后再合并这些文件。

示例:分批写入临时文件并合并

use think\facade\Db;

// 设置导出文件名
$fileName = 'export_' . date('YmdHis') . '.csv';

// 设置每页大小
$pageSize = 1000;
$totalCount = Db::name('your_table')->count();
$pageCount = ceil($totalCount / $pageSize);

// 打开最终的输出文件
$finalFp = fopen('php://output', 'w');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="' . $fileName . '"');

for ($page = 1; $page <= $pageCount; $page++) {
    // 创建临时文件
    $tempFile = tempnam(sys_get_temp_dir(), 'csv');
    $tempFp = fopen($tempFile, 'w');

    // 查询并写入临时文件
    $dataList = Db::name('your_table')
        ->limit(($page - 1) * $pageSize, $pageSize)
        ->select();

    // 写入 CSV 表头(仅第一页)
    if ($page == 1) {
        fputcsv($tempFp, ['ID', 'Name', 'Age', 'Email']);
    }

    foreach ($dataList as $row) {
        fputcsv($tempFp, $row);
    }

    fclose($tempFp);
    unset($dataList);

    // 读取临时文件并写入最终输出文件
    $tempFp = fopen($tempFile, 'r');
    while ($line = fgets($tempFp)) {
        fwrite($finalFp, $line);
    }
    fclose($tempFp);
    unlink($tempFile);  // 删除临时文件
}

fclose($finalFp);
exit();

4. 使用 Excel 或其它格式导出

除了 CSV 格式,你还可以使用 PHPExcelPhpSpreadsheet 等库导出为 Excel 文件。对于大数据量,PhpSpreadsheet 提供了 setReadDataOnlystream 方法来减少内存占用。

示例:使用 PhpSpreadsheet 导出 Excel

composer require phpoffice/phpspreadsheet
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\facade\Db;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// 设置表头
$sheet->fromArray([
    ['ID', 'Name', 'Age', 'Email'],
], null, 'A1');

// 分页查询并写入数据
$pageSize = 1000;
$totalCount = Db::name('your_table')->count();
$pageCount = ceil($totalCount / $pageSize);
$row = 2;  // 从第二行开始写入数据

for ($page = 1; $page <= $pageCount; $page++) {
    $dataList = Db::name('your_table')
        ->limit(($page - 1) * $pageSize, $pageSize)
        ->select();

    $sheet->fromArray($dataList, null, 'A' . $row);
    $row += count($dataList);
    unset($dataList);
}

// 设置导出文件名
$fileName = 'export_' . date('YmdHis') . '.xlsx';

// 直接输出到浏览器
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $fileName . '"');
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
exit();

总结

  1. 分批查询并导出:适合数据量较大但仍在可控范围内的情况。
  2. 队列导出:适合超大数据量,使用后台任务分批处理并导出。
  3. 临时文件分批写入:适合非常大的数据量,通过临时文件减少内存占用。
  4. 使用 PhpSpreadsheet 导出 Excel:适合需要导出复杂格式的情况。

根据你的数据量和需求,选择合适的导出方式可以有效提高导出效率并避免内存溢出问题。

标签: none

非特殊说明,本博所有文章均为博主原创。

评论啦~



已有 38 条评论


  1. ehxswhupqc
    ehxswhupqc

    这篇文章不错!

    回复 2025-03-07 11:53
  2. wrynzwrcse
    wrynzwrcse

    这篇文章不错!

    回复 2025-03-07 01:44
  3. cxhjzgdutg
    cxhjzgdutg

    这篇文章不错!

    回复 2025-03-07 00:42
  4. aozlptkrgf
    aozlptkrgf

    这篇文章不错!

    回复 2025-03-07 00:23
  5. lebgxuqljy
    lebgxuqljy

    这篇文章不错!

    回复 2025-03-06 23:05
  6. bhkdquuukl
    bhkdquuukl

    文章紧扣主题,观点鲜明,展现出深刻的思考维度。

    回复 2025-03-04 16:16
  7. nqzlzlvzgz
    nqzlzlvzgz

    这篇文章如同一首动人的乐章,触动了读者内心深处的柔软。

    回复 2025-03-04 16:16
  8. piddddpppd
    piddddpppd

    作者的布局谋篇匠心独运,让读者在阅读中享受到了思维的乐趣。

    回复 2025-03-04 16:02
  9. yvnrggrhdj
    yvnrggrhdj

    字里行间流露出真挚的情感,让人感同身受,共鸣不已。

    回复 2025-03-04 15:43
  10. zflzjuhndq
    zflzjuhndq

    这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。

    回复 2025-03-04 15:33
  11. dimnoninvo
    dimnoninvo

    案例丰富且贴合主题,论证逻辑环环相扣。

    回复 2025-03-03 00:23
  12. pdgwwxwwwt
    pdgwwxwwwt

    文章中的实用建议和操作指南,让读者受益匪浅,值得珍藏。

    回复 2025-03-02 17:47
  13. dfqxrrpgne
    dfqxrrpgne

    文章结构紧凑,层次分明,逻辑严密,让人一读即懂。

    回复 2025-03-02 17:33
  14. sgwplffgsc
    sgwplffgsc

    作者的情感表达细腻入微,让人在阅读中找到了心灵的慰藉。

    回复 2025-03-02 17:18
  15. gpyilcdutl
    gpyilcdutl

    这篇文章如同一幅色彩斑斓的画卷,每一笔都充满了独特的创意。

    回复 2025-03-02 17:04
  16. xwqqbrtrro
    xwqqbrtrro

    每一个段落都紧密相连,逻辑清晰,展现了作者高超的写作技巧。

    回复 2025-03-02 16:40
  17. awgmbmcljh
    awgmbmcljh

    技术原理阐述透彻,配图辅助理解到位。

    回复 2025-03-01 11:05
  18. ciwsfvmapy
    ciwsfvmapy

    网络流行语融入自然,贴近年轻读者。

    回复 2025-03-01 07:54
  19. sgcgcbnzws
    sgcgcbnzws

    文献引用规范,学术态度严谨,值得借鉴。

    回复 2025-03-01 05:16
  20. gmjtuspgob
    gmjtuspgob

    跨界融合的尝试为文章注入新鲜活力。

    回复 2025-03-01 03:16
  21. nltuzkoals
    nltuzkoals

    文献引用规范,学术态度严谨,值得借鉴。

    回复 2025-02-28 22:05
  22. ylqkrzgkyc
    ylqkrzgkyc

    情感浓度过高可适当留白,以达平衡。

    回复 2025-02-28 21:51
  23. xqxheclayf
    xqxheclayf

    文化符号解读精准,展现独特审美。

    回复 2025-02-28 21:33
  24. nzizxippae
    nzizxippae

    意象选取精妙,营造出空灵意境。

    回复 2025-02-28 21:22
  25. lgfoyxhlxa
    lgfoyxhlxa

    技术前瞻性分析体现行业敏感度。

    回复 2025-02-28 21:07
  26. hasyzrrlkn
    hasyzrrlkn

    建议补充性能优化方案,增强实用性。

    回复 2025-02-28 21:07
  27. baldfhhlqc
    baldfhhlqc

    对生命本质的追问充满哲学思辨。

    回复 2025-02-28 20:54
  28. nkzosdyrei
    nkzosdyrei

    学术术语使用精准,专业性突出。

    回复 2025-02-28 20:34
  29. daagzotisv
    daagzotisv

    建议补充国内外研究对比,以拓展视野。

    回复 2025-02-28 20:34
  30. iqrgxkbuoe
    iqrgxkbuoe

    这篇文章如同一幅色彩斑斓的画卷,每一笔都充满了独特的创意。

    回复 2025-02-28 18:40
  31. hsrbtnuxsn
    hsrbtnuxsn

    作者的才华横溢,让这篇文章成为了一篇不可多得的艺术品。

    回复 2025-02-28 18:02
  32. zvkqafxsog
    zvkqafxsog

    作者对主题的挖掘深入骨髓,展现了非凡的洞察力和理解力。

    回复 2025-02-28 16:36
  33. ryagvyqvrx
    ryagvyqvrx

    作者以非凡的视角解读平凡,让文字焕发出别样的光彩。

    回复 2025-02-28 16:36
  34. xwsgedbari
    xwsgedbari

    建议提出分阶段实施路径,增强可行性。

    回复 2025-02-28 16:24
  35. pkdxylkkym
    pkdxylkkym

    文字流畅如丝,语言优美动人,读来令人心旷神怡。

    回复 2025-02-28 16:22
  36. ellbjxzakd
    ellbjxzakd

    若能结合热点事件分析,会更富时代性。

    回复 2025-02-28 15:32
  37. oeilxzoblb
    oeilxzoblb

    选材新颖独特,通过细节描写赋予主题鲜活生命力。

    回复 2025-02-28 15:22
  38. ahjnqkdmev
    ahjnqkdmev

    文章紧扣主题,观点鲜明,展现出深刻的思考维度。

    回复 2025-02-28 15:22