首页 文章

使用Excel OleDb获取工作表名称IN SHEET ORDER

提问于
浏览
99

我正在使用OleDb从包含许多工作表的excel工作簿中读取 .

我需要阅读工作表名称,但我需要按照电子表格中定义的顺序进行操作;所以如果我有一个看起来像这样的文件;

|_____|_____|____|____|____|____|____|____|____|
|_____|_____|____|____|____|____|____|____|____|
|_____|_____|____|____|____|____|____|____|____|
\__GERMANY__/\__UK__/\__IRELAND__/

然后我需要得到字典

1="GERMANY", 
2="UK", 
3="IRELAND"

我尝试过使用 OleDbConnection.GetOleDbSchemaTable() ,这给了我名单,但按字母顺序对它们进行排序 . 字母排序意味着我不知道特定名称对应于哪个表格编号 . 所以我得到了;

GERMANY, IRELAND, UK

这改变了 UKIRELAND 的顺序 .

我需要对它进行排序的原因是我必须让用户按名称或索引选择一系列数据;他们可以要求“从德国到爱尔兰的所有数据”或“从表1到表3的数据” .

任何想法将不胜感激 .

如果我可以使用办公室互操作课程,这将是直截了当的 . 不幸的是,我不能,因为互操作类在非交互式环境(如Windows服务和ASP.NET站点)中不能可靠地工作,所以我需要使用OLEDB .

11 回答

  • 8

    这对我有用 . 从这里被盗:How do you get the name of the first page of an excel workbook?

    object opt = System.Reflection.Missing.Value;
    Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
    Excel.Workbook workbook = app.Workbooks.Open(WorkBookToOpen,
                                             opt, opt, opt, opt, opt, opt, opt,
                                             opt, opt, opt, opt, opt, opt, opt);
    Excel.Worksheet worksheet = workbook.Worksheets[1] as Microsoft.Office.Interop.Excel.Worksheet;
    string firstSheetName = worksheet.Name;
    
  • 6

    在实际的MSDN文档中找不到这个,但论坛中的主持人说

    我担心OLEDB不像Excel中那样保留工作表顺序

    Excel Sheet Names in Sheet Order

    似乎这是一个普遍的要求,将有一个体面的解决方法 .

  • 5

    你能不能只是将表格从0循环到名字-1的计数?那样你应该按照正确的顺序得到它们 .

    Edit

    我通过评论注意到,使用Interop类检索工作表名称存在很多问题 . 因此,这是一个使用OLEDB检索它们的示例:

    /// <summary>
    /// This method retrieves the excel sheet names from 
    /// an excel workbook.
    /// </summary>
    /// <param name="excelFile">The excel file.</param>
    /// <returns>String[]</returns>
    private String[] GetExcelSheetNames(string excelFile)
    {
        OleDbConnection objConn = null;
        System.Data.DataTable dt = null;
    
        try
        {
            // Connection String. Change the excel file to the file you
            // will search.
            String connString = "Provider=Microsoft.Jet.OLEDB.4.0;" + 
              "Data Source=" + excelFile + ";Extended Properties=Excel 8.0;";
            // Create connection object by using the preceding connection string.
            objConn = new OleDbConnection(connString);
            // Open connection with the database.
            objConn.Open();
            // Get the data table containg the schema guid.
            dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
    
            if(dt == null)
            {
               return null;
            }
    
            String[] excelSheets = new String[dt.Rows.Count];
            int i = 0;
    
            // Add the sheet name to the string array.
            foreach(DataRow row in dt.Rows)
            {
               excelSheets[i] = row["TABLE_NAME"].ToString();
               i++;
            }
    
            // Loop through all of the sheets if you want too...
            for(int j=0; j < excelSheets.Length; j++)
            {
                // Query each excel sheet.
            }
    
            return excelSheets;
       }
       catch(Exception ex)
       {
           return null;
       }
       finally
       {
          // Clean up.
          if(objConn != null)
          {
              objConn.Close();
              objConn.Dispose();
          }
          if(dt != null)
          {
              dt.Dispose();
          }
       }
    }
    

    从CodeProject上的Article中提取 .

  • 2

    由于上述代码不包括提取Excel 2007工作表名称列表的过程,因此以下代码也适用于Excel(97-2003)和Excel 2007:

    public List<string> ListSheetInExcel(string filePath)
    {
       OleDbConnectionStringBuilder sbConnection = new OleDbConnectionStringBuilder();
       String strExtendedProperties = String.Empty;
       sbConnection.DataSource = filePath;
       if (Path.GetExtension(filePath).Equals(".xls"))//for 97-03 Excel file
       {
          sbConnection.Provider = "Microsoft.Jet.OLEDB.4.0";
          strExtendedProperties = "Excel 8.0;HDR=Yes;IMEX=1";//HDR=ColumnHeader,IMEX=InterMixed
       }
       else if (Path.GetExtension(filePath).Equals(".xlsx"))  //for 2007 Excel file
       {
          sbConnection.Provider = "Microsoft.ACE.OLEDB.12.0";
          strExtendedProperties = "Excel 12.0;HDR=Yes;IMEX=1";
       }
       sbConnection.Add("Extended Properties",strExtendedProperties);
       List<string> listSheet = new List<string>();
       using (OleDbConnection conn = new OleDbConnection(sbConnection.ToString()))
       {
         conn.Open();
         DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);         
         foreach (DataRow drSheet in dtSheet.Rows)
         {
            if (drSheet["TABLE_NAME"].ToString().Contains("$"))//checks whether row contains '_xlnm#_FilterDatabase' or sheet name(i.e. sheet name always ends with $ sign)
            {
                 listSheet.Add(drSheet["TABLE_NAME"].ToString());
            } 
         }
      }
     return listSheet;
    }
    

    上面的函数返回两个excel类型(97,2003,2007)的特定excel文件的工作表列表 .

  • 0

    其他方式:

    xls(x)文件只是存储在* .zip容器中的* .xml文件的集合 . 解压缩docProps文件夹中的文件“app.xml” .

    <?xml version="1.0" encoding="UTF-8" standalone="true"?>
    -<Properties xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
    <TotalTime>0</TotalTime>
    <Application>Microsoft Excel</Application>
    <DocSecurity>0</DocSecurity>
    <ScaleCrop>false</ScaleCrop>
    -<HeadingPairs>
      -<vt:vector baseType="variant" size="2">
        -<vt:variant>
          <vt:lpstr>Arbeitsblätter</vt:lpstr>
        </vt:variant>
        -<vt:variant>
          <vt:i4>4</vt:i4>
        </vt:variant>
      </vt:vector>
    </HeadingPairs>
    -<TitlesOfParts>
      -<vt:vector baseType="lpstr" size="4">
        <vt:lpstr>Tabelle3</vt:lpstr>
        <vt:lpstr>Tabelle4</vt:lpstr>
        <vt:lpstr>Tabelle1</vt:lpstr>
        <vt:lpstr>Tabelle2</vt:lpstr>
      </vt:vector>
    </TitlesOfParts>
    <Company/>
    <LinksUpToDate>false</LinksUpToDate>
    <SharedDoc>false</SharedDoc>
    <HyperlinksChanged>false</HyperlinksChanged>
    <AppVersion>14.0300</AppVersion>
    </Properties>
    

    该文件是德语文件(Arbeitsblätter= worksheets) . 表名(Tabelle3等)的顺序正确 . 你只需要阅读这些标签;)

    问候

  • 22

    我使用@kraeppy(https://stackoverflow.com/a/19930386/2617732)答案中提供的信息创建了以下函数 . 这需要使用.net framework v4.5,并且需要引用System.IO.Compression . 这仅适用于xlsx文件,不适用于较旧的xls文件 .

    using System.IO.Compression;
        using System.Xml;
        using System.Xml.Linq;
    
        static IEnumerable<string> GetWorksheetNamesOrdered(string fileName)
        {
            //open the excel file
            using (FileStream data = new FileStream(fileName, FileMode.Open))
            {
                //unzip
                ZipArchive archive = new ZipArchive(data);
    
                //select the correct file from the archive
                ZipArchiveEntry appxmlFile = archive.Entries.SingleOrDefault(e => e.FullName == "docProps/app.xml");
    
                //read the xml
                XDocument xdoc = XDocument.Load(appxmlFile.Open());
    
                //find the titles element
                XElement titlesElement = xdoc.Descendants().Where(e => e.Name.LocalName == "TitlesOfParts").Single();
    
                //extract the worksheet names
                return titlesElement
                    .Elements().Where(e => e.Name.LocalName == "vector").Single()
                    .Elements().Where(e => e.Name.LocalName == "lpstr")
                    .Select(e => e.Value);
            }
        }
    
  • 17

    这是简短,快速,安全和可用的......

    public static List<string> ToExcelsSheetList(string excelFilePath)
    {
        List<string> sheets = new List<string>();
        using (OleDbConnection connection = 
                new OleDbConnection((excelFilePath.TrimEnd().ToLower().EndsWith("x")) 
                ? "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + excelFilePath + "';" + "Extended Properties='Excel 12.0 Xml;HDR=YES;'"
                : "provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + exceladdress + "';Extended Properties=Excel 8.0;"))
        {
            connection.Open();
            DataTable dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
            foreach (DataRow drSheet in dt.Rows)
                if (drSheet["TABLE_NAME"].ToString().Contains("$"))
                {
                    string s = drSheet["TABLE_NAME"].ToString();
                    sheets.Add(s.StartsWith("'")?s.Substring(1, s.Length - 3): s.Substring(0, s.Length - 1));
                }
            connection.Close();
        }
        return sheets;
    }
    
  • 1

    我喜欢@deathApril将页面命名为1_Germany,2_UK,3_IRELAND的想法 . 我也有你的问题,重命名数百张 . 如果重命名工作表名称没有问题,则可以使用此宏为您执行此操作 . 重命名所有工作表名称只需不到几秒钟 . 不幸的是,ODBC,OLEDB通过asc返回工作表名称顺序 . 没有替代品 . 您必须使用COM或重命名您的名称 .

    Sub Macro1()
    '
    ' Macro1 Macro
    '
    
    '
    Dim i As Integer
    For i = 1 To Sheets.Count
     Dim prefix As String
     prefix = i
     If Len(prefix) < 4 Then
      prefix = "000"
     ElseIf Len(prefix) < 3 Then
      prefix = "00"
     ElseIf Len(prefix) < 2 Then
      prefix = "0"
     End If
     Dim sheetName As String
     sheetName = Sheets(i).Name
     Dim names
     names = Split(sheetName, "-")
     If (UBound(names) > 0) And IsNumeric(names(0)) Then
      'do nothing
     Else
      Sheets(i).Name = prefix & i & "-" & Sheets(i).Name
     End If
    Next
    
    End Sub
    

    更新:在阅读@SidHoland关于BIFF的评论之后,一个想法闪现了 . 可以通过代码完成以下步骤 . 不知道你是否真的想这样做以获得相同顺序的工作表名称 . 如果您需要帮助以通过代码执行此操作,请告诉我们 .

    1. Consider XLSX as a zip file. Rename *.xlsx into *.zip
    2. Unzip
    3. Go to unzipped folder root and open /docprops/app.xml
    4. This xml contains the sheet name in the same order of what you see.
    5. Parse the xml and get the sheet names
    

    更新:另一个解决方案 - NPOI在这里可能会有所帮助http://npoi.codeplex.com/

    FileStream file = new FileStream(@"yourexcelfilename", FileMode.Open, FileAccess.Read);
    
          HSSFWorkbook  hssfworkbook = new HSSFWorkbook(file);
            for (int i = 0; i < hssfworkbook.NumberOfSheets; i++)
            {
                Console.WriteLine(hssfworkbook.GetSheetName(i));
            }
            file.Close();
    

    此解决方案适用于xls . 我没有尝试xlsx .

    谢谢,

    也先

  • 0

    试试这个 . 以下是按顺序获取工作表名称的代码 .

    private Dictionary<int, string> GetExcelSheetNames(string fileName)
    {
        Excel.Application _excel = null;
        Excel.Workbook _workBook = null;
        Dictionary<int, string> excelSheets = new Dictionary<int, string>();
        try
        {
            object missing = Type.Missing;
            object readOnly = true;
            Excel.XlFileFormat.xlWorkbookNormal
            _excel = new Excel.ApplicationClass();
            _excel.Visible = false;
            _workBook = _excel.Workbooks.Open(fileName, 0, readOnly, 5, missing,
                missing, true, Excel.XlPlatform.xlWindows, "\\t", false, false, 0, true, true, missing);
            if (_workBook != null)
            {
                int index = 0;
                foreach (Excel.Worksheet sheet in _workBook.Sheets)
                {
                    // Can get sheet names in order they are in workbook
                    excelSheets.Add(++index, sheet.Name);
                }
            }
        }
        catch (Exception e)
        {
            return null;
        }
        finally
        {
            if (_excel != null)
            {
    
                if (_workBook != null)
                    _workBook.Close(false, Type.Missing, Type.Missing);
                _excel.Application.Quit();
            }
            _excel = null;
            _workBook = null;
        }
        return excelSheets;
    }
    
  • 1

    根据MSDN,在Excel中的电子表格的情况下,它可能无法工作,因为Excel文件不是真正的数据库 . 因此,您将无法按工作簿中的可视化顺序获取工作表名称 .

    使用interop根据视觉外观获取工作表名称的代码:

    添加对Microsoft Excel 12.0对象库的引用 .

    以下代码将以工作簿中存储的实际顺序给出工作表名称,而不是已排序的名称 .

    示例代码:

    using Microsoft.Office.Interop.Excel;
    
    string filename = "C:\\romil.xlsx";
    
    object missing = System.Reflection.Missing.Value;
    
    Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
    
    Microsoft.Office.Interop.Excel.Workbook wb =excel.Workbooks.Open(filename,  missing,  missing,  missing,  missing,missing,  missing,  missing,  missing,  missing,  missing,  missing,  missing,  missing,  missing);
    
    ArrayList sheetname = new ArrayList();
    
    foreach (Microsoft.Office.Interop.Excel.Worksheet  sheet in wb.Sheets)
    {
        sheetname.Add(sheet.Name);
    }
    
  • 71

    我没有看到任何文档说app.xml中的顺序保证是工作表的顺序 . 它可能是,但不是根据OOXML规范 .

    另一方面,workbook.xml文件包含sheetId属性,确定序列 - 从1到工作表数 . 这是根据OOXML规范 . workbook.xml被描述为保留工作表序列的位置 .

    因此,从XLSX中提取后读取workbook.xml将是我的建议 . 不是app.xml . 而不是docProps / app.xml,使用xl / workbook.xml并查看元素,如下所示 -

    `

    <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
      <fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303" /> 
      <workbookPr defaultThemeVersion="124226" /> 
    - <bookViews>
      <workbookView xWindow="120" yWindow="135" windowWidth="19035" windowHeight="8445" /> 
      </bookViews>
    - <sheets>
      <sheet name="By song" sheetId="1" r:id="rId1" /> 
      <sheet name="By actors" sheetId="2" r:id="rId2" /> 
      <sheet name="By pit" sheetId="3" r:id="rId3" /> 
      </sheets>
    - <definedNames>
      <definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'By song'!$A$1:$O$59</definedName> 
      </definedNames>
      <calcPr calcId="145621" /> 
      </workbook>
    

    `

相关问题