无法在 C# 中使用 Gembox 加载 .xls 文件

Unable to load .xls file using Gembox in C#

我想使用 C# 加载 .xls 文件(类型:97-2003 电子表格)。 我正在使用 Gembox 库。

当我使用下面的命令时,遇到错误“文件包含损坏的数据。”。

ExcelFile ef = ExcelFile.Load(filepath, XlsxLoadOptions.XlsxDefault);

当我删除 XlsxLoadOptions 参数时出现“读取错误:文件不是有效的 OLE2 复合文件。

我是 C# 新手,无法调试问题的根本原因。 请帮忙!

更新 (2020-03-28)

在 GemBox.Spreadsheet 的较新版本中,ExcelFile.Load(String) 将在“.xls”文件的情况下检查文件的签名。
换句话说,不再需要下面的 GetLoadOptions 方法。

此外,还有一个新的重载方法,ExcelFile.Load(Stream)
这将始终检查提供的流中的文件签名。

原版

评论中回答了这个问题。不幸的是,它在那里不是很明显,所以这里是答案和一些关于它的额外细节。

GemBox.Spreadsheet 提供很少 Load overload methods。使用以下内容时:

ExcelFile ef = ExcelFile.Load("C://temp//book.xls");

结果如下:

ExcelFile ef = ExcelFile.Load("C://temp//book.xls", LoadOptions.XlsDefault);

与下面的相同:

ExcelFile ef = ExcelFile.Load("C://temp//book.xls", new XlsLoadOptions());

加载选项指定如何读取输入文件,以及使用 ExcelFile.Load(String) 方法时,选项将基于文件的扩展名。

在本例中,文件的扩展名为“.xls”,但它不是二进制 XLS 格式 (BIFF8),而是 HTML 格式。这是一个比较常用的技巧,你可以有HTML、CSV,甚至扩展名为“.xls”的XLSX文件,MS Excel都可以打开它。它会检测正确的文件格式,并会提示用户类似以下消息:

File format and extension of 'book.xls' don't match. The file could be corrupted or unsafe. Unless you trust its source, don't open it. Do you want to open it anyway?

请注意,此技巧仅适用于“.xls”扩展名,不适用于“.xlsx”等扩展名。然而,我们可以使用类似下面的方法来检测正确的文件格式:

private static LoadOptions GetLoadOptions(string path)
{
    string extension = Path.GetExtension(path).ToUpperInvariant();
    switch (extension)
    {
        case ".XLSX":
        case ".XLSM":
        case ".XLTX":
        case ".XLTM":
            return LoadOptions.XlsxDefault;
        case ".XLS":
        case ".XLT":
            return GetLoadOptions(path, null);
        case ".ODS":
        case ".OTS":
            return LoadOptions.OdsDefault;
        case ".TAB":
        case ".TSV":
            return new CsvLoadOptions(CsvType.TabDelimited);
        case ".CSV":
            return LoadOptions.CsvDefault;
        default:
            return null;
    }
}

private static LoadOptions GetLoadOptions(string xlsPath, LoadOptions defaultOptions)
{
    byte[] signature = new byte[8];
    using (var stream = File.OpenRead(xlsPath))
        stream.Read(signature, 0, 8);

    byte[] xlsSignature = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
    if (signature.SequenceEqual(xlsSignature))
        return LoadOptions.XlsDefault;

    byte[] xlsxSignature = new byte[] { 0x50, 0x4B, 0x03, 0x04 };
    if (signature.Take(4).SequenceEqual(xlsxSignature))
        return LoadOptions.XlsxDefault;

    string firstLine = File.ReadLines(xlsPath)
        .First(line => !string.IsNullOrWhiteSpace(line)).TrimStart().ToUpperInvariant();
    if (firstLine.StartsWith("<!DOCTYPE") ||
        firstLine.StartsWith("<HTML") ||
        firstLine.StartsWith("<BODY"))
        return LoadOptions.HtmlDefault;

    return defaultOptions;
}

这里还有一个关于如何使用它的小演示示例:

string filepath = "C://temp//book.xls";
LoadOptions options = GetLoadOptions(filepath);

if (options == null)
    throw new FileFormatException();

ExcelFile ef = ExcelFile.Load(filepath, options);
// ...