【问题标题】:How to get list of ONLY excel worksheet names in Excel using OLEDB; filter out non-worksheets that show up in metadata如何使用 OLEDB 在 Excel 中获取仅 Excel 工作表名称的列表;过滤掉出现在元数据中的非工作表
【发布时间】:2012-05-18 14:24:25
【问题描述】:

我在使用 OLEDB 从 Excel 电子表格中获取工作表名称时遇到问题。问题是当我使用 GetOleDbSchemaTable 时,生成的 DataTable 不仅仅是实际的工作表名称;它有额外的“表格”行,我只能假设 Excel 在内部使用这些行。

例如,如果我有一个名为 myWorksheet 的工作表,下面的代码可能会以包含 myWorksheet$、myWorksheet$PrintTable 和 myWorksheet$_ 的列表结束。只有第一个 myWorksheet$ 记录用于实际工作表。其他的只是我不需要的垃圾。当您在元数据中查看它们时,它们看起来就像常规表,即使是 TABLE 类型。

目前我只是手动过滤掉名称中带有“$_”或“$Print”的任何内容,但谁知道其他 Excel 功能可能会使这些额外记录以不同的格式出现。

有谁知道仅获取实际工作表名称而不是这些不是工作表的内部表的最佳方法?元数据中有什么东西可以区分它们吗?

 private ArrayList getXlsWorksheetNames(OleDb.OleDbConnection conn)
    {
        ArrayList wsList = new ArrayList();
        DataTable schemaTable;

        try
        {
            conn.Open();
            schemaTable = conn.GetOleDbSchemaTable(OleDb.OleDbSchemaGuid.Tables, null);

            foreach (DataRow row in schemaTable.Rows)
            {
                //form.appendToResultsTxt("Adding worksheet to list: " + Environment.NewLine +
                //    "Name = " + row.Field<string>("TABLE_NAME") + "," + Environment.NewLine +
                //    "Type = " + row.Field<string>("TABLE_TYPE") + "," + Environment.NewLine + Environment.NewLine);
                wsList.Add(row.Field<string>("TABLE_NAME"));
            }
            conn.Close();
        }
        catch (Exception ex)
        {
            if (this.mode == Cps2TxtUtilModes.GUI_MODE)
            {
                this.form.appendToResultsTxt(ex.ToString());
            }
            throw;
        }

        return wsList;
    }

我通读了此链接上的文章,但他们似乎没有做任何与我不同的事情,而且我没有看到任何过滤掉额外的非工作表表格,所以微软似乎没有提供了正确的答案。

http://support.microsoft.com/kb/318452

我还查看了很多 StackOverflow,比如下面链接中的线程,它很有帮助,但并没有解决这个问题。

Using Excel OleDb to get sheet names IN SHEET ORDER

在有人问之前,我还想说,我无法真正控制电子表格中使用的功能,所以我不能只告诉他们“不要打开过滤”或“不要'不使用打印表"。

非常感谢任何想法。谢谢!

【问题讨论】:

  • 只过滤掉任何不带“$”的东西。我已经使用了一段时间,它从未失败过,即使有数据透视表、过滤列表等。
  • 谢谢;我会去做。就像我在下面的评论中所说的那样,这不太理想,因为它依赖于实现细节,但如果这是我必须要做的,那就这样吧。
  • 我对您在上面链接的问题的回答显示了如何使用 DAO 来做到这一点,但如果您不想使用 COM,那么这不是一个选择。但是,Esen 对答案的附录显示了另一种方法,即将 .xlsx 重命名为 .zip、打开 zip 文件内容并读取其中的一个 xml 文件以获取工作表名称。我还没有测试过隐藏的工作表是否出现在那里,它只适用于 2007 (.xlsx) 文件,但它可能值得一试。
  • 好消息 Sid,但不幸的是我必须支持 Excel 2003,而且我绝对不想使用 COM / interop。很高兴知道 XLSX 文件可以重命名为 zip 并打开以获取一些元数据宝石。希望小费对其他人有所帮助;它可能会在未来的某个时候对我有所帮助,但对这个项目没有帮助。
  • 仅供参考,供所有可能查看此内容以供将来参考的人使用。如果工作表的名称中有空格,则元数据中的表名将用单引号括起来,这意味着 $ 不会是表名中的最后一个字符,即使它是有效的工作表。因此,仅查找以 $ 作为最后一个字符的所有内容是不够的。您必须首先删除任何周围的单个 qoutes,然后评估 $ 是否是最后一个字符。这至少可以说是蹩脚的。为什么 Microsoft 不在元数据中包含表示用户工作表的内容?

标签: c# excel oledb


【解决方案1】:

这个问题很老了,但对于那些现在发现它的人来说,跳过可以像 Jim 发现的那样完成......

// skip those that do not end correctly
foreach (DataRow row in schemTable.Rows)
{
    string sheetName = row["TABLE_NAME"].ToString();
    if (!sheetName.EndsWith("$") && !sheetName.EndsWith("$'"))
        continue;
    Console.WriteLine(sheetName);
}

那是想要的或者以$ 结尾的或者以$' 结尾的那些。

【讨论】:

    【解决方案2】:

    根据经验,似乎是所有名字以美元符号结尾的人。我遇到过来自客户的场景,其中似乎出现了数据中不存在的额外工作表 - 后来证明这些工作表是 Excel 中的隐藏工作表!

    【讨论】:

    • 是的,这些“隐藏”表是导致问题的原因。您可能是对的,我可以将“$”作为名称中的最后一个字符。但是,其中一些“隐藏”表的名称中确实有 $,我更多的是寻找一种明确的方法来从某些元数据属性中判断“表”是工作表,还是其他类型的内部使用的 Excel桌子。无论如何,感谢您的回答。还有其他人知道 Excel 元数据中有什么可以区分的吗?
    • 我还没有找到一种方法来只查看哪些表是可见的,我猜我们需要使用 Interop 来完成类似的事情。 GetOleDbSchemaTable 表中没有任何内容可以区分它们。如果您确实找到了一些东西,请分享,我也会更新我的程序!
    • 绝对不想使用互操作!谢谢你的信息。我一直很警惕,也许有一些我不知道的功能会导致一个非工作表“表”在名称末尾有一个 $,但我想现在就足够了假设情况并非如此。不过,依赖实现细节很糟糕。
    • 嗨,吉姆,我遇到了同样的问题,令人沮丧。对于这个特定问题,您找到了合适的解决方案吗?
    • @Tejas,对不起,到目前为止,我唯一的解决方案是依赖于 $ 的实现细节是最后一个字符,或者单引号是最后一个字符的 hacky 方式字符,那么 $ 将是倒数第二个字符。我和你一样生气!为什么我们必须依赖这样的实现细节?太傻了。
    【解决方案3】:

    我想到的第一种方式与链接中列出的 akash88 相同 Using Excel OleDb to get sheet names IN SHEET ORDER链接。

    您可以采用 akash88 的方法并稍微清理一下,以便代码更易于阅读。

            var wsList = from s in schemaTable
                         where s.Field<string>("TABLE_NAME").Contains("$")
                         select s.Field<string>("TABLE_NAME");
    

    【讨论】:

    • 请阅读整篇文章和 cmets,您会发现您的答案并不充分;它将返回 Excel 内部表(如过滤表)的额外记录。原始帖子特别提到了这一点,并特别要求一种从元数据中仅获取实际用户工作表的方法。自发布此文章以来,我发现没有标准方法可以从元数据中分辨出来,除非依靠实现细节,即所有用户工作表都有一个 $ 作为最后一个字符,或者如果名称有空格,则倒数第二个字符和因此被双引号包围。
    【解决方案4】:

    您可以测试EndsWith("$") 而不是Contains("$"),如下所示:

    List<String> lstsheetNames = new List<String>();
    String sheetName;
    foreach (DataRow row in schemaTable.Rows)
    {
        sheetName = row.Field<string>("TABLE_NAME");
        String strTemp = sheetName.Split(' ');
    
        if(strTemp.Length == 1 && sheetName.EndsWith("$"))
           lstsheetNames.Add(sheetName.Substring(0, sheetName.Length - 1));
    
        else if(strTemp.Length > 1 && strTemp.GetValue(strTemp.Length - 1).ToString().EndsWith("$'"))
           lstsheetNames.Add(sheetName.Substring(1, sheetName.Length - 3));
    }
    

    我在同样的问题中使用过这段代码,它工作正常。

    编辑:对不起,我没有注意这个。我现在更改了代码。它可能不是最好或最短的方法,但它可以工作。

    【讨论】:

    • 没有人阅读实际的帖子吗?我已经多次提到,如果表名有空格,这将不起作用,因为它将以引号而不是 $ 结尾,我还特别要求提供一个真正的解决方案,其中元数据指示用户表而不是一个内部表,而不是仅仅依赖于我已经非常清楚地知道存在的实现细节,因为它在我的 OP 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多