spatie/simple-excel

读取和写入简单的Excel和CSV文件

资助包维护!
spatie

安装次数: 4,271,801

依赖项: 38

建议者: 0

安全性: 0

星标: 1,161

关注者: 21

分支: 131

3.6.0 2024-04-24 13:41 UTC

README

Latest Version on Packagist GitHub Workflow Status Total Downloads

此包允许您轻松读取和写入简单的Excel和CSV文件。在幕后,使用生成器确保即使处理大文件时,内存使用量也较低。

以下是如何读取Excel或CSV的示例。

use Spatie\SimpleExcel\SimpleExcelReader;

SimpleExcelReader::create($pathToFile)->getRows()
   ->each(function(array $rowProperties) {
        // process the row
    });

如果 $pathToFile.csv 结尾,则假定是CSV文件。如果以 .xlsx 结尾,则假定是Excel文件。

支持我们

我们投入了大量资源来创建最佳开源包。您可以通过购买我们的付费产品之一来支持我们。

我们非常感谢您从家乡寄给我们明信片,并说明您正在使用我们的哪个包。您可以在我们的联系页面找到我们的地址。我们将所有收到的明信片发布在我们的虚拟明信片墙上

安装

您可以通过composer安装此包

composer require spatie/simple-excel

用法

读取CSV

假设您有一个包含以下内容的CSV文件。

email,first_name
john@example.com,john
jane@example.com,jane
use Spatie\SimpleExcel\SimpleExcelReader;

// $rows is an instance of Illuminate\Support\LazyCollection
$rows = SimpleExcelReader::create($pathToCsv)->getRows();

$rows->each(function(array $rowProperties) {
   // in the first pass $rowProperties will contain
   // ['email' => 'john@example.com', 'first_name' => 'john']
});

读取Excel文件

读取Excel文件与读取CSV文件相同。只需确保传递给 SimpleExcelReadercreate 方法的路径以 xlsx 结尾即可。

使用LazyCollections

getRows 将返回一个 Illuminate\Support\LazyCollection 的实例。此类是Laravel框架的一部分。在幕后使用生成器,因此即使对于大文件,内存使用量也将保持较低。

您可以在Laravel文档中找到可以在 LazyCollection 上使用的列表。

以下是一个快速、愚蠢的示例,其中我们只想处理具有超过5个字符的 first_name 的行。

SimpleExcelReader::create($pathToCsv)->getRows()
    ->filter(function(array $rowProperties) {
       return strlen($rowProperties['first_name']) > 5;
    })
    ->each(function(array $rowProperties) {
        // processing rows
    });

读取无标题行的文件

如果您正在读取的文件不包含标题行,则应使用 noHeaderRow() 方法。

// $rows is an instance of Illuminate\Support\LazyCollection
$rows = SimpleExcelReader::create($pathToCsv)
    ->noHeaderRow()
    ->getRows()
    ->each(function(array $rowProperties) {
       // in the first pass $rowProperties will contain
       // [0 => 'john@example', 1 => 'john']
});

手动设置标题

如果您想使用特定数组值作为标题,可以使用 useHeaders() 方法。

// $rows is an instance of Illuminate\Support\LazyCollection
$rows = SimpleExcelReader::create($pathToCsv)
    ->useHeaders(['email_address', 'given_name'])
    ->getRows()
    ->each(function(array $rowProperties) {
       // in the first pass $rowProperties will contain
       // ['email_address' => 'john@example', 'given_name' => 'john']
});

如果您的文件已经包含标题行,它将被忽略并替换为您的自定义标题。

如果您的文件不包含标题行,您还应该使用 noHeaderRow(),并且您的标题将像上面那样代替数字键。

处理多工作表文档

Excel文件可以包含多个工作表。您可以使用 fromSheet() 方法通过索引选择您想要使用的工作表。

$rows = SimpleExcelReader::create($pathToXlsx)
    ->fromSheet(3)
    ->getRows();

对于多个工作表,您也可以使用 fromSheetName() 方法通过名称选择您想要使用的工作表。

$rows = SimpleExcelReader::create($pathToXlsx)
    ->fromSheetName("sheet1")
    ->getRows();

如果您想检查工作表是否存在,请使用 hasSheet() 方法。

$hasSheet = SimpleExcelReader::create($pathToXlsx)
    ->hasSheet("sheet1");

检索标题行值

如果您想将标题行作为数组检索,请使用 getHeaders() 方法。

如果您使用过 useHeaders() 来设置自定义头,那么将返回这些头而不是文件的实际头。要获取文件中的原始头,请使用 getOriginalHeaders()

$headers = SimpleExcelReader::create($pathToCsv)->getHeaders();

// $headers will contain
// [ 'email', 'first_name' ]

处理不在第一行的头

如果您的文件中的头不在第一行,您可以使用 headerOnRow() 方法来指示头所在的行。任何在此行之上的数据都将从结果中丢弃。

headerOnRow 接受行号作为参数,从 0 开始。空行不计入。

由于空行不计入,此方法主要用于包含实际数据集上方格式的文件,例如 Excel 文件。

This is my data sheet
See worksheet 1 for the data, worksheet 2 for the graphs.



email , firstname
john@example.com,john
jane@example.com,jane
// $rows is an instance of Illuminate\Support\LazyCollection
$rows = SimpleExcelReader::create($pathToCsv)
    ->trimHeaderRow()
    ->headerOnRow(3)
    ->getRows()
    ->each(function(array $rowProperties) {
       // in the first pass $rowProperties will contain
       // ['email' => 'john@example', 'first_name' => 'john']
});

修剪头

如果您正在读取的文件包含标题行,但需要在标题值上修剪额外字符,则应使用 trimHeaderRow() 方法。此功能模仿 trim 方法,并且默认要修剪的字符与该函数匹配。

想象您有一个包含以下内容的 csv 文件。

email , first_name
john@example.com,john
jane@example.com,jane
// $rows is an instance of Illuminate\Support\LazyCollection
$rows = SimpleExcelReader::create($pathToCsv)
    ->trimHeaderRow()
    ->getRows()
    ->each(function(array $rowProperties) {
       // in the first pass $rowProperties will contain
       // ['email' => 'john@example', 'first_name' => 'john']
});

trimHeaderRow() 还接受一个参数来指定要修剪的字符。此参数可以使用与 trim 函数的 $characters 定义相同的函数。

将头转换为 snake_case

如果您希望所有头都转换为 snake_case,请使用 headersToSnakeCase() 方法。

Email,First Name,Last Name
john@example.com,john,doe
mary-jane@example.com,mary jane,doe
$rows = SimpleExcelReader::create($pathToCsv)
    ->headersToSnakeCase()
    ->getRows()
    ->each(function(array $rowProperties) {
        // rowProperties converted to snake_case
        // ['email' => 'john@example', 'first_name' => 'John', 'last_name' => 'doe']
    });

手动格式化头

您可以使用自定义格式化器通过 formatHeadersUsing 方法并传递一个闭包来更改头。

email,first_name,last_name
john@example.com,john,doe
mary-jane@example.com,mary jane,doe
$rows = SimpleExcelReader::create($pathToCsv)
    ->formatHeadersUsing(fn($header) => "{$header}_simple_excel")
    ->getRows()
    ->each(function(array $rowProperties) {
        // ['email_simple_excel' => 'john@example', 'first_name_simple_excel' => 'John', 'last_name_simple_excel' => 'doe']
    });

手动处理读取器对象

在内部,此包使用 box/spout 包。您可以通过调用 getReader 方法来获取实现 \OpenSpout\Reader\ReaderInterface 的底层读取器。

$reader = SimpleExcelReader::create($pathToCsv)->getReader();

限制结果集

take 方法允许您指定要返回的行数限制。

// $rows is an instance of Illuminate\Support\LazyCollection
$rows = SimpleExcelReader::create($pathToCsv)
    ->take(5)
    ->getRows();

skip 方法允许您定义从哪一行开始读取数据。在此示例中,我们获取第 11 行到第 16 行。

$rows = SimpleExcelReader::create($pathToCsv)
    ->skip(10)
    ->take(5)
    ->getRows();

读取包含公式的单元格

通常,包含公式的单元格会被解析,并且它们的计算值将被返回。如果您想将实际的公式作为字符串保留,请使用 keepFormulas 方法。

$rows = SimpleExcelReader::create($pathToXlsx)
    ->keepFormulas()
    ->getRows();

写入文件

这是写入 CSV 文件的方法

use Spatie\SimpleExcel\SimpleExcelWriter;

$writer = SimpleExcelWriter::create($pathToCsv)
     ->addRow([
        'first_name' => 'John',
        'last_name' => 'Doe',
    ])
    ->addRow([
        'first_name' => 'Jane',
        'last_name' => 'Doe',
    ]);

位于 pathToCsv 的文件将包含

first_name,last_name
John,Doe
Jane,Doe

从数组手动设置头

您不必让包自动检测标题行,可以手动设置它。

use Spatie\SimpleExcel\SimpleExcelWriter;

$writer = SimpleExcelWriter::create($pathToCsv)
    ->addHeader(['first_name', 'last_name'])
    ->addRow(['John', 'Doe'])
    ->addRow(['Jane', 'Doe'])

写入 Excel 文件

写入 Excel 文件与写入 csv 相同。只需确保给 SimpleExcelWritercreate 方法的路径以 xlsx 结尾。在写入 Excel 文件时要注意的另一件事是,文件不会在 SimpleExcelWriter 实例被垃圾回收之前写入。那时将调用 close 方法。close 方法是最终将文件写入磁盘的方法。如果您需要在实例被垃圾回收之前访问文件,您需要先调用 close 方法。

$writer->close();

将 Excel 文件流式传输到浏览器

您可以直接将文件流式传输到浏览器,而不是将其写入磁盘。

$writer = SimpleExcelWriter::streamDownload('your-export.xlsx')
     ->addRow([
        'first_name' => 'John',
        'last_name' => 'Doe',
    ])
    ->addRow([
        'first_name' => 'Jane',
        'last_name' => 'Doe',
    ])
    ->toBrowser();

如果您向浏览器发送大型流,请确保调用 flush()

$writer = SimpleExcelWriter::streamDownload('your-export.xlsx');

foreach (range(1, 10_000) as $i) {
    $writer->addRow([
        'first_name' => 'John',
        'last_name' => 'Doe',
    ]);
    
    if ($i % 1000 === 0) {
        flush(); // Flush the buffer every 1000 rows
    }
}
    
$writer->toBrowser();

您还可以使用回调。

use Spatie\SimpleExcel\SimpleExcelWriter;
use OpenSpout\Common\Entity\Row;

$writer = SimpleExcelWriter::streamDownload('user-list.xlsx', function ($writerCallback, $downloadName) {
    
    $writerCallback->openToBrowser($downloadName);

    $writerCallback->addRow(Row::fromValues([
        'first_name' => 'First Name',
        'last_name' => 'Last Name',
    ]));

    $writerCallback->addRow(Row::fromValues([
        'first_name' => 'Rakib',
        'last_name' => 'Hossain',
    ]));

    foreach (range(1, 10_000) as $i) {
        $writerCallback->addRow(Row::fromValues([
            'first_name' => 'Rakib',
            'last_name' => 'Hossain',
        ]));

        if ($i % 1000 === 0) {
            flush();
        }
    }
});

$writer->toBrowser();

一次写入多行

您可以使用 addRows 而不是 addRow 来一次添加多行。

$writer = SimpleExcelWriter::streamDownload('your-export.xlsx')
     ->addRows([
        [
            'first_name' => 'John',
            'last_name' => 'Doe',
        ],
        [
            'first_name' => 'Jane',
            'last_name' => 'Doe',
        ],
    ]);

写入不带标题的文件

如果您正在编写的文件不应该自动添加标题行,则应使用 noHeaderRow() 方法。

$writer = SimpleExcelWriter::create($pathToCsv)
    ->noHeaderRow()
    ->addRow([
        'first_name' => 'Jane',
        'last_name' => 'Doe',
    ]);

这将输出

Jane,Doe

添加布局

在底层,此包使用 openspout/openspout 包。该包包含一个 Style 构建器,您可以使用它来格式化行。样式只能在 Excel 文档中使用。

use OpenSpout\Common\Entity\Style\Color;
use OpenSpout\Common\Entity\Style\CellAlignment;
use OpenSpout\Common\Entity\Style\Style;
use OpenSpout\Common\Entity\Style\Border;
use OpenSpout\Common\Entity\Style\BorderPart;

/* Create a border around a cell */
$border = new Border(
        new BorderPart(Border::BOTTOM, Color::LIGHT_BLUE, Border::WIDTH_THIN, Border::STYLE_SOLID),
        new BorderPart(Border::LEFT, Color::LIGHT_BLUE, Border::WIDTH_THIN, Border::STYLE_SOLID),
        new BorderPart(Border::RIGHT, Color::LIGHT_BLUE, Border::WIDTH_THIN, Border::STYLE_SOLID),
        new BorderPart(Border::TOP, Color::LIGHT_BLUE, Border::WIDTH_THIN, Border::STYLE_SOLID)
    );
    
$style = (new Style())
   ->setFontBold()
   ->setFontSize(15)
   ->setFontColor(Color::BLUE)
   ->setShouldWrapText()
   ->setBackgroundColor(Color::YELLOW)
   ->setBorder($border);

$writer->addRow(['values', 'of', 'the', 'row'], $style);

要格式化标题行,只需调用 setHeaderStyle($style) 方法。

$writer->setHeaderStyle($style);

有关样式的更多信息,请访问 Spout 文档

设置列宽和行高

通过访问底层 OpenSpout Writer,您可以设置默认列宽和行高,并更改特定列的宽度。

SimpleExcelWriter::create(
    file: 'document.xlsx',
    configureWriter: function ($writer) {
        $options = $writer->getOptions();
        $options->DEFAULT_COLUMN_WIDTH=25; // set default width
        $options->DEFAULT_ROW_HEIGHT=15; // set default height
        // set columns 1, 3 and 8 to width 40
        $options->setColumnWidth(40, 1, 3, 8);
        // set columns 9 through 12 to width 10
        $options->setColumnWidthForRange(10, 9, 12);
    }
)

创建额外的工作表

默认情况下,编写器将写入第一个工作表。如果您想写入额外的工作表,可以使用 addNewSheetAndMakeItCurrent 方法。

$writer = SimpleExcelWriter::create($pathToXlsx);

Posts::all()->each(function (Post $post) use ($writer) {
    $writer->nameCurrentSheet($post->title);
    
    $post->comments->each(function (Comment $comment) use ($writer) {
        $writer->addRow([
            'comment' => $comment->comment,
            'author' => $comment->author,
        ]);
    });
    
    if(!$post->is($posts->last())) {
        $writer->addNewSheetAndMakeItCurrent();
    }
});

使用替代分隔符

默认情况下,SimpleExcelReader 将假设分隔符是 ,

这是您如何使用替代分隔符的方法

SimpleExcelWriter::create(file: $pathToCsv, delimiter: ';');

获取已写入的行数

您可以获取已写入的行数。此数字包括自动添加的标题行。

$writerWithAutomaticHeader = SimpleExcelWriter::create($this->pathToCsv)
    ->addRow([
        'first_name' => 'John',
        'last_name' => 'Doe',
    ]);

$writerWithAutomaticHeader->getNumberOfRows(); // returns 2

禁用 BOM

您还可以禁用在文件开头添加 BOM。必须在创建时禁用 BOM,并且创建编写器后不能禁用。

BOM(字节顺序标记)表示正在写入的文件的一些内容,包括文件是 Unicode 以及其 UTF 编码类型。

SimpleExcelWriter::createWithoutBom($this->pathToCsv, $type);

有关 BOM 的更多信息,请参阅 此处

手动处理编写器对象

在底层,此包使用 openspout/openspout 包。您可以通过调用 getWriter 方法来访问实现 \OpenSpout\Reader\WriterInterface 的底层编写器。

$writer = SimpleExcelWriter::create($pathToCsv)->getWriter();

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 变更日志

贡献

有关详细信息,请参阅 贡献指南

安全性

如果您发现了关于安全性的错误,请通过 security@spatie.be 邮件联系,而不是使用问题跟踪器。

明信片软件

您可以自由使用此包,但如果它进入了您的生产环境,我们非常欢迎您从家乡寄给我们一张明信片,注明您正在使用我们的哪个包。

我们的地址是:Spatie,Kruikstraat 22,2018 安特卫普,比利时。

我们将发布所有收到的明信片 在我们的公司网站上

鸣谢

替代方案

许可

MIT 许可证(MIT)。有关更多信息,请参阅 许可文件