如何从Excel(.xlsb)二进制文件格式中读取数据?

8

我正在使用POI 3.9从xlsx文件中读取数据。但是现在我遇到了一个问题,即POI不支持xlsb文件的读取,而我需要以程序方式读取xlsb文件中的数据。有人知道如何以程序方式读取xlsb文件中的数据吗?感激不尽。

5个回答

4

使用poi,您可以将XLSB读取到数据库、结构(XML等)、内容列表等等。
以下代码将XLSB转换为行/注释列表和映射额外信息的列表。
您可以根据需要自定义代码。


请在链接中查找许多示例,感谢poi的作者们。

// 主类

package excel;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.binary.XSSFBSharedStringsTable;
import org.apache.poi.xssf.binary.XSSFBSheetHandler;
import org.apache.poi.xssf.binary.XSSFBStylesTable;
import org.apache.poi.xssf.eventusermodel.XSSFBReader;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class Excel {

    public static void main (String [] args){

        String xlsbFileName = "C:\\Users\\full path to .xlsb file";
        callXLToList(xlsbFileName);        
    }

    static void callXLToList(String xlsbFileName){
        OPCPackage pkg;
        try {
            pkg = OPCPackage.open(xlsbFileName);
            XSSFBReader r = new XSSFBReader(pkg);
            XSSFBSharedStringsTable sst = new XSSFBSharedStringsTable(pkg);
            XSSFBStylesTable xssfbStylesTable = r.getXSSFBStylesTable();
            XSSFBReader.SheetIterator it = (XSSFBReader.SheetIterator) r.getSheetsData();

            List<XLSB2Lists> workBookAsList = new ArrayList<>();
            int sheetNr = 1;
            while (it.hasNext()) {
                InputStream is = it.next();
                String name = it.getSheetName();

                System.out.println("Begin parsing sheet "+sheetNr+": "+name);

                XLSB2Lists testSheetHandler = new XLSB2Lists();
                testSheetHandler.startSheet(name);
                XSSFBSheetHandler sheetHandler = new XSSFBSheetHandler(is,
                        xssfbStylesTable,
                        it.getXSSFBSheetComments(),
                        sst, testSheetHandler,
                        new DataFormatter(),
                        false);
                sheetHandler.parse();
                testSheetHandler.endSheet();

                System.out.println("End parsing sheet "+sheetNr+": "+name);
                sheetNr++;

                // Add parsed sheet to workbook list
                workBookAsList.add(testSheetHandler);
            }

            // For every sheet in Workbook
            System.out.println("\nShort Report:");
            for(XLSB2Lists sheet:workBookAsList){
                // sheet content
                System.out.println("Size of content: " +sheet.getSheetContentAsList().size());
                // sheet comment
                System.out.println("Size fo comment: "+sheet.getSheetCommentAsList().size());
                // sheet extra info
                System.out.println("Extra info.: "+sheet.getMapOfInfo().toString());                
            }

        } catch (InvalidFormatException e) {
            // TODO Please do your catch hier
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Please do your catch hier
            e.printStackTrace();
        } catch (OpenXML4JException e) {
            // TODO Please do your catch hier
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Please do your catch hier
            e.printStackTrace();
        }
    }
}

// 解析类

package excel;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;

/**
 *
 * @author Dominique
 */
public class XLSB2Lists implements XSSFSheetXMLHandler.SheetContentsHandler {

    private final List sheetAsList = new ArrayList<>();
    private List rowAsList;
    private final List sheetCommentAsList = new ArrayList<>();
    private List rowCommentAsList;
    private final Map propertyMap = new HashMap<>();

    public void startSheet(String sheetName) {
        propertyMap.put("sheetName", sheetName);
    }

    @Override
    public void startRow(int rowNum) {
        rowAsList = new ArrayList<>();
        rowCommentAsList = new ArrayList<>();
    }

    @Override
    public void endRow(int rowNum) {
        sheetAsList.add(rowNum, rowAsList);
        sheetCommentAsList.add(rowNum, rowCommentAsList);
    }

    @Override
    public void cell(String cellReference, String formattedValue, XSSFComment comment) {
        formattedValue = (formattedValue == null) ? "" : formattedValue;
        rowAsList.add(formattedValue);
        if (comment == null) {
            rowCommentAsList.add("");
        } else {
            propertyMap.put("comment author at "+comment.getRow()+":"+cellReference, comment.getAuthor());
            rowCommentAsList.add(comment.getString().toString().trim());
        }
    }

    @Override
    public void headerFooter(String text, boolean isHeader, String tagName) {
        if (isHeader) {
            propertyMap.put("header tag", tagName);
            propertyMap.put("header text", text);
        } else { // footer
            propertyMap.put("header tag", tagName);
            propertyMap.put("header text", text);
        }
    }

    public List getSheetContentAsList(){
        return sheetAsList;
    }

    public List getSheetCommentAsList(){
        return sheetCommentAsList;
    }

    public Map getMapOfInfo(){
        return propertyMap;
    }
}

2

Apache POI在3.16版本中增加了对XLSB的流式读取支持(不支持写入)。Apache Tika 1.15现在支持从XLSB中提取内容。


1
在Perl中,Win32::OLE模块可以将XLSB转换为XLSX。缺点是:您必须安装MS Excel。以下是基于我使用的示例代码...
use File::Spec::Functions qw/rel2abs/;
use Win32::OLE;
use Win32::OLE::Const 'Microsoft Excel';
use Win32::OLE::Variant;

Win32::OLE->Option( Warn => 3 );

my $xlsb = 'C:\Users\wohlfarj\Documents\File.xlsb';

# This block uses an already open instance of Excel, or starts a new one if it isn't already open.
my $excel;
eval { $excel = Win32::OLE->GetActiveObject('Excel.Application') };
  die 'MS Excel not installed' if $@;

unless (defined $excel) {
  $excel = Win32::OLE->new( 'Excel.Application', 'Quit' )
    or die 'Cannot start MS Excel';
}

# After all of the setup, converting the file is painless.
my $xlsx = rel2abs( $xlsb );
$xlsx =~ s/\.xlsb$/\.xlsx/i;

my $workbook = $excel->Workbooks->Open( {FileName => rel2abs( $xlsb )} );
$workbook->SaveAs( {FileFormat => xlOpenXMLWorkbook, Filename => $xlsx} );
$workbook->Close( {SaveChanges => xlDoNotSaveChanges} );

从这里开始,Spreadsheet::XLSX 模块可以很好地读取 XLSX 文件副本。

-1

POI开发人员似乎没有计划支持XLSB格式:http://mail-archives.apache.org/mod_mbox/poi-dev/201401.mbox/%3Calpine.DEB.2.02.1401250721280.31868%40urchin.earth.li%3E

这需要相当多的工作,因为您需要更新记录以应对更长/不同的格式,然后重新处理所有编组工作以处理非常不同的方式。到目前为止,没有人想要为非常边缘的好处投入所有这些工作。

似乎有一个用于读取xlsb的javascript库,您可以使用它将数据导出为JSON并从Java中读取。


1
在POI上,我们刚刚添加了一个xlsb文件的只读流解析器。它将在3.16-beta3中提供。 - Tim Allison

-4

这只是一个解决方法...

您可以将xlsb文件转换为xlsx文件,然后使用POI从中提取数据。

您试过了吗?我知道这不是正确的答案,但希望能有所帮助。:)


是的,但问题在于如何通过编程方式将xlsb转换为xlsx? - Martin
Apache POI不支持.xlsb文件格式,因此从xlsx转换为xlsb可能在语法上不可行。我想需要更多时间进行研究。 - Benil Mathew
可以使用Microsoft Excel驱动程序来读取它。但我并不是很喜欢它——成为Microsoft的奴隶。 - Martin
有人知道是否有第三方驱动程序可用于xlsb吗? - Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接