不幸的是,如果不加载整个文件,就无法读取工作表的名称。
在调用 setLoadSheetsOnly() 时使用索引号而不是名称不会给出可预测的结果:执行该检查的代码逻辑使用 in_array() 来测试它要读取的工作表名是否在工作表名数组中读。例如
// check if sheet should be skipped
if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
continue;
}
我怀疑在执行此测试时(基于 PHP 的松散类型和比较转换规则),字符串与数值的比较将给出 0 == "mySheetName" 的真实结果。
我可能会提供一个 Reader 方法,该方法将返回工作表名称列表,而无需实际加载整个文件,尽管会影响性能。
编辑
如果将以下方法添加到 Classes/PHPExcel/Reader/Excel2007.php
/**
* Reads names of the worksheets from a file, without loading the whole file to a PHPExcel object
*
* @param string $pFilename
* @throws Exception
*/
public function listWorksheetNames($pFilename)
{
// Check if file exists
if (!file_exists($pFilename)) {
throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
}
$worksheetNames = array();
$zip = new ZipArchive;
$zip->open($pFilename);
$rels = simplexml_load_string($this->_getFromZipArchive($zip, "_rels/.rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships");
foreach ($rels->Relationship as $rel) {
switch ($rel["Type"]) {
case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
$xmlWorkbook = simplexml_load_string($this->_getFromZipArchive($zip, "{$rel['Target']}")); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
if ($xmlWorkbook->sheets) {
foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
// Check if sheet should be skipped
$worksheetNames[] = (string) $eleSheet["name"];
}
}
}
}
$zip->close();
return $worksheetNames;
}
您可以使用以下方法调用它:
$inputFileType = 'Excel2007';
$inputFileName = 'biostat-behfisk-2005.xlsx';
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$worksheetNames = $objReader->listWorksheetNames($inputFileName);
foreach ($worksheetNames as $sheetName) {
echo $sheetName, '<br />';
}
返回的 $worksheetNames 应该包含一个所有工作表名称的数组作为 UTF-8 字符串。因为它只是从 .xlsx 中读取绝对最小值来检索这些名称,所以它应该相当快。在将其检入 PHPExcel SVN 之前,我会进行更多测试,但(目前)它似乎可以满足您的需求。
编辑2
Excel5 Reader 的等效方法
/**
* Reads names of the worksheets from a file, without loading the whole file to a PHPExcel object
*
* @param string $pFilename
* @throws Exception
*/
public function listWorksheetNames($pFilename)
{
// Check if file exists
if (!file_exists($pFilename)) {
throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
}
$worksheetNames = array();
// Read the OLE file
$this->_loadOLE($pFilename);
// total byte size of Excel data (workbook global substream + sheet substreams)
$this->_dataSize = strlen($this->_data);
$this->_pos = 0;
$this->_sheets = array();
// Parse Workbook Global Substream
while ($this->_pos < $this->_dataSize) {
$code = self::_GetInt2d($this->_data, $this->_pos);
switch ($code) {
case self::XLS_Type_BOF: $this->_readBof(); break;
case self::XLS_Type_SHEET: $this->_readSheet(); break;
case self::XLS_Type_EOF: $this->_readDefault(); break 2;
default: $this->_readDefault(); break;
}
}
foreach ($this->_sheets as $sheet) {
if ($sheet['sheetType'] != 0x00) {
// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
continue;
}
$worksheetNames[] = $sheet['name'];
}
return $worksheetNames;
}
效率不如 Excel2007 Reader 版本,但仍比仅针对工作表名称解析整个 .xls 文件要快,因为我只解析全局流。