导出excel的几种方式

1.CSV
缺点:在遇到文件内容中包含逗号的时候可能会错乱。。。

    public function export(RequestInterface $request){
        $head = ['name'=>'名字','score'=>'得分'];
        $data = [
            ['name' => '张三', 'score' => '80'],
            ['name' => '李四', 'score' => '90'],
            ['name' => '王五', 'score' => '60'],
        ];
        $head_keys = array_keys($head);
        $head_values = array_values($head);
        $fileData = mb_convert_encoding(implode(',', $head_values),"GBK","UTF-8") . "\n";

        foreach ($data as $value) {
            $temp_arr = [];
            foreach ($head_keys as $key) {
                $temp_arr[] = $value[$key] ?? '';
            }
            ;
            $fileData .= mb_convert_encoding(implode(',', $temp_arr),"GBK","UTF-8") . "\n";
        }
        $contentType = 'text/csv';
        return $this->response->withHeader('content-description', 'File Transfer')
            ->withHeader('content-type', $contentType)
            ->withHeader('content-disposition', "attachment; filename=test")
            ->withHeader('content-transfer-encoding', 'binary')
            ->withHeader('pragma', 'public')
            ->withBody(new SwooleStream($fileData));
    }

2.phpoffice/phpspreadsheet composer包处理
缺点:数据量大的时候很慢

    public function testDownload()
    {
        $fileName ='test.xls';
        $fieldList = ['name'=>'名字','score'=>'得分'];
        $dataList = [
            ['name' => '张三', 'score' => '80'],
            ['name' => '李四', 'score' => '90'],
            ['name' => '王五', 'score' => '60'],
        ];
        $workSheet = new Worksheet();
        //sheet名称定义
        $workSheet->setTitle('sheet1');
        //第一行写入头信息
        $columnIndex = 1;
        foreach ($fieldList as $fieldName){
            $excelKey = Coordinate::stringFromColumnIndex($columnIndex);
            $workSheet->setCellValue($excelKey.'1',$fieldName);
            $columnIndex++;
        }
        //遍历数据写入表格
        foreach ($dataList as $k=>$data){
            $columnIndex = 1;
            $rowIndex = $k+2;
            foreach ($fieldList as $field=>$fieldName){
                $excelKey = Coordinate::stringFromColumnIndex($columnIndex);
                $workSheet->setCellValue($excelKey.$rowIndex,$data[$field]??"");
                $columnIndex++;
            }
        }
        //创建excel文件类
        $spreadsheet = new Spreadsheet();
        $spreadsheet->addSheet($workSheet,0);
        $spreadsheet->setActiveSheetIndex(0);
        $writer = IOFactory::createWriter($spreadsheet,IOFactory::WRITER_XLSX);
        $filePath = BASE_PATH .'/excel/'.$fileName;
        $writer->save($filePath);
        $fileName = rawurlencode($fileName);
        $response = $this->response->withHeader('Content-Type', 'application/octet-stream')
            ->withHeader('Content-Disposition', 'attachment;filename="' . $fileName . '"')
            ->withHeader('Access-Control-Expose-Headers', 'Content-Disposition');

        // 将文件内容写入响应流
        $response->getBody()->write(file_get_contents($filePath));

        return $response;

    }

3.xlswriter扩展
支持百万级数据导出
缺点:数据查询的功能最好效率比较高,最好做成异步

    public function test()
    {

        $header = [
            [
                'field' => 'name',
                'desc' => "姓名"
            ],
            [
                'field' => 'score',
                'desc' => "分数"
            ]
        ];
        $excel = new Excel([
            'path' => BASE_PATH . '/runtime/'
        ]);
        $fileName = date('YmdHis').".xlsx";
        $textFile = $excel->fileName($fileName)->header(array_column($header,'desc'));
        $page = 1;
        $row = 1;
        do{
            $total = $nextPage=0;
            //获取数据与是否有下一页数据
            $dataList = [
                ['name' => '张三', 'score' => '80'],
                ['name' => '李四', 'score' => '90'],
                ['name' => '王五', 'score' => '60'],
            ];
            //遍历数据
            foreach ($dataList as $k=>$item) {
                foreach ($header as $index=>$headerItem){
                    $field = $headerItem['field'];
                    $textFile->insertText($row, $index, $item[$field]??'');
                }
                $row++;
            }

            $next = false;
            if($nextPage>$page){
                $next = true;
                $page = $nextPage;
            }
        }while($next);
        //写入文件
        $filePath = $textFile->output();

        $fileName = rawurlencode($fileName);
        $response = $this->response->withHeader('Content-Type', 'application/octet-stream')
            ->withHeader('Content-Disposition', 'attachment;filename="' . $fileName . '"')
            ->withHeader('Access-Control-Expose-Headers', 'Content-Disposition');

        // 将文件内容写入响应流
        $response->getBody()->write(file_get_contents($filePath));
        return $response;
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 4

xlswriter 我导出过千万数据,但是我发现生成的文件很大

3个月前 评论
向前一步 (楼主) 3个月前

csv的逗号不算多大的问题,fputcsv可以指定分隔符的。

3个月前 评论
向前一步 (楼主) 3个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!