代码之家  ›  专栏  ›  技术社区  ›  Steve Cooper

使用Excel OleDb按图纸顺序获取图纸名称

  •  99
  • Steve Cooper  · 技术社区  · 15 年前

    我正在使用OleDb阅读包含许多工作表的excel工作簿。

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

    那我得去拿字典

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

    我试过使用 OleDbConnection.GetOleDbSchemaTable() ,这给了我一张名单,但它按字母顺序排列。alpha排序意味着我不知道特定名称对应的页码。所以我得到了;

    GERMANY, IRELAND, UK
    

    UK IRELAND .

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

    任何想法都将不胜感激。

    如果我可以使用office互操作类,这将非常简单。不幸的是,我不能,因为互操作类在非交互环境(如windows服务和ASP.NET站点)中不能可靠地工作,所以我需要使用OLEDB。

    11 回复  |  直到 15 年前
        1
  •  79
  •   James    15 年前

    你能不能不从0到名字计数-1的循环表?这样你就可以把它们按正确的顺序排列。

    编辑

    /// <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();
          }
       }
    }
    

    摘自 Article 在这个项目上。

        2
  •  23
  •   TruthOf42    8 年前

    由于上述代码不包括提取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类型(9720032007)的特定excel文件中的工作表列表。

        3
  •  19
  •   Jeremy Breece    12 年前

    在实际的MSDN文档中找不到这个,但论坛的一位版主说

    恐怕OLEDB不能像在Excel中那样保留图纸顺序

    Excel Sheet Names in Sheet Order

    似乎这将是一个足够普遍的要求,有一个体面的解决办法。

        4
  •  10
  •   MiMFa    5 年前

    这是简短、快速、安全和可用的。。。

    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='" + excelFilePath + "';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;
    }
    
        5
  •  8
  •   kraeppy    11 年前

    另一种方式:

    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=工作表)。 表名(表3等)的顺序正确。您只需要阅读这些标记;)

    当做

        6
  •  6
  •   Community CDub    7 年前

    我使用@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);
            }
        }
    
        7
  •  2
  •   Esen    12 年前

    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。

    谢谢

    埃森

        8
  •  1
  •   imsome1    6 年前

    这对我有用。从这里偷来的: 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;
    
        9
  •  1
  •   MiMFa    6 年前

    试试这个。以下是按顺序获取图纸名称的代码。

    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;
    }
    
        10
  •  0
  •   Romil Kumar Jain    12 年前

    根据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);
    }
    
        11
  •  0
  •   Vern Hamberg    10 年前

    另一方面,workbook.xml文件包含sheetId属性,该属性确定从1到工作表数量的顺序。这符合OOXML规范。xml被描述为保存工作表顺序的地方。

    因此,我建议在从XLSX中提取工作簿.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>