Verwenden von Excel OleDb zum Abrufen von Blattnamen IN BLATTORDNUNG


103

Ich verwende OleDb, um aus einer Excel-Arbeitsmappe mit vielen Blättern zu lesen.

Ich muss die Blattnamen lesen, aber ich brauche sie in der Reihenfolge, in der sie in der Tabelle definiert sind. Also, wenn ich eine Datei habe, die so aussieht;

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

Dann muss ich das Wörterbuch bekommen

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

Ich habe versucht, zu verwenden OleDbConnection.GetOleDbSchemaTable(), und das gibt mir die Liste der Namen, aber es sortiert sie alphabetisch. Die Alpha-Sortierung bedeutet, dass ich nicht weiß, welcher Blattnummer ein bestimmter Name entspricht. Also bekomme ich;

GERMANY, IRELAND, UK

das hat die Reihenfolge von UKund geändert IRELAND.

Der Grund, warum ich es sortieren muss, ist, dass ich den Benutzer einen Datenbereich nach Name oder Index auswählen lassen muss; Sie können nach "allen Daten von DEUTSCHLAND nach IRLAND" oder "Daten von Blatt 1 nach Blatt 3" fragen.

Irgendwelche Ideen wären sehr dankbar.

Wenn ich die Office-Interop-Klassen nutzen könnte, wäre dies unkompliziert. Leider kann ich das nicht, da die Interop-Klassen in nicht interaktiven Umgebungen wie Windows-Diensten und ASP.NET-Sites nicht zuverlässig funktionieren. Daher musste ich OLEDB verwenden.


Welche Version der Excel-Datei lesen Sie?
Yamen

30
wow , wie hast du das machen und wie hast du die Geduld , dass zu ziehen
l --''''''--------- ‚‘ ‚‘ ‚‘ ‚‘ ‚‘ ‚‘

4
@ АртёмЦарионов - das sind Reihen vertikaler Balken (|) und Unterstriche (_) für die Tabelle sowie Schrägstriche (\ /) für die Registerkarten. Kopieren Sie es in einen Texteditor und Sie werden sehen.
Sid Holland

Antworten:


17

Ich kann dies nicht in der aktuellen MSDN-Dokumentation finden, aber ein Moderator in den Foren sagte

Ich befürchte, dass OLEDB die Blattreihenfolge nicht wie in Excel beibehält

Excel-Blattnamen in Blattreihenfolge

Dies scheint eine häufig genug erforderliche Voraussetzung für eine angemessene Problemumgehung zu sein.


Dies antwortete jedoch direkt, es spart viel Zeit bei unnötigen Versuchen.
Shihe Zhang

75

Können Sie nicht einfach die Blätter von 0 bis Anzahl der Namen -1 durchlaufen? Auf diese Weise sollten Sie sie in der richtigen Reihenfolge erhalten.

Bearbeiten

Ich habe durch die Kommentare festgestellt, dass es viele Bedenken gibt, die Interop-Klassen zum Abrufen der Blattnamen zu verwenden. Daher hier ein Beispiel, in dem OLEDB zum Abrufen verwendet wird:

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

Auszug aus dem Artikel über das CodeProject.


Das ist Code, den ich gerne sehen würde! Wie können Sie das 'N-te Blatt' und die Anzahl der Blätter abfragen?
Steve Cooper

13
Hallo James. Dies ist so ziemlich mein ursprüngliches Problem - während die GetOleDbSchemaTable () -Methode die Namen abruft, entspricht die Zeilennummer nicht der Arbeitsmappenblattnummer. Blatt 4 wäre also Zeile 0, wenn es im Alphabet an erster Stelle stünde.
Steve Cooper

23
Beantwortet keine Posterfrage (er möchte sie in der Reihenfolge ihres Auftretens in Excel)
Andrew White

7
@Samuel Ich glaube nicht, dass es das Problem des OP direkt gelöst hat, aber es scheint vielen anderen bei einem ähnlichen Problem zu helfen.
James

1
Löst nicht die Frage des OP, nach der ich gesucht habe. (Ich poste immer den Grund für eine Ablehnung.)
Phil Nicholas

23

Da der obige Code keine Verfahren zum Extrahieren der Liste der Blattnamen für Excel 2007 abdeckt, gilt der folgende Code sowohl für Excel (97-2003) als auch für 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;
}

Die obige Funktion gibt eine Liste der Blätter in einer bestimmten Excel-Datei für beide Excel-Typen (97.2003.2007) zurück.


11
Dieser Code gibt die Blätter nicht in der Reihenfolge zurück, in der sie in Excel erscheinen
Andrew White

10

Dies ist kurz, schnell, sicher und verwendbar ...

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;
}

Funktioniert nicht "out of the box". exceladdress- Was ist das?
Michael Hutter

8

Ein anderer Weg:

Eine xls (x) -Datei ist nur eine Sammlung von * .xml-Dateien, die in einem * .zip-Container gespeichert sind. Entpacken Sie die Datei "app.xml" im Ordner docProps.

<?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>

Die Datei ist eine deutsche Datei (Arbeitsblätter). Die Tabellennamen (Tabelle3 usw.) sind in der richtigen Reihenfolge. Sie müssen nur diese Tags lesen;)

Grüße


1
Dies funktioniert gut für XLSX-Dateien, jedoch nicht für XLS-Dateien. Sie haben nicht die gleiche Struktur. Wissen Sie, wie dieselben Daten aus einer XLS-Datei extrahiert werden können?
rdans

6

Ich habe die folgende Funktion unter Verwendung der Informationen erstellt, die in der Antwort von @kraeppy ( https://stackoverflow.com/a/19930386/2617732 ) angegeben sind. Dies erfordert die Verwendung des .net Framework v4.5 und einen Verweis auf System.IO.Compression. Dies funktioniert nur für XLSX-Dateien und nicht für ältere XLS-Dateien.

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

2

Ich mag die Idee von @deathApril, die Blätter als 1_Germany, 2_UK, 3_IRELAND zu benennen. Ich habe auch Ihr Problem, diese Umbenennung für Hunderte von Blättern durchzuführen. Wenn Sie keine Probleme haben, den Blattnamen umzubenennen, können Sie dieses Makro verwenden, um dies für Sie zu tun. Das Umbenennen aller Blattnamen dauert weniger als Sekunden. Leider gibt ODBC, OLEDB die Blattnamenreihenfolge per ASC zurück. Dafür gibt es keinen Ersatz. Sie müssen entweder COM verwenden oder Ihren Namen umbenennen, um in der Reihenfolge zu sein.

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

UPDATE: Nach dem Lesen des @ SidHoland-Kommentars zu BIFF kam eine Idee auf. Die folgenden Schritte können über Code ausgeführt werden. Ich weiß nicht, ob Sie das wirklich tun möchten, um die Blattnamen in derselben Reihenfolge zu erhalten. Lassen Sie mich wissen, wenn Sie Hilfe benötigen, um dies durch Code zu tun.

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

UPDATE: Eine andere Lösung - NPOI könnte hier hilfreich sein 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();

Diese Lösung funktioniert für xls. Ich habe xlsx nicht ausprobiert.

Vielen Dank,

Esen


1
Sie müssen nicht haben , um die Blätter zu umbenennen oder nur COM verwenden, da meine Antwort zeigt Sie DAO verwenden können. Ich denke, es könnte auch eine Möglichkeit geben, sie durch Lesen des BIFF abzurufen , aber ich untersuche das immer noch.
Sid Holland

1
@SidHolland: DAO ist eine COM-Komponente. Die Verwendung der COM-Komponente in Server 2008 ist ein Problem, daher ging Steve mit ADO.NET
Esen

Mein Gehirn hat nicht gedacht, dass DAO eine COM-Komponente ist, obwohl ich es als COM-Referenz hinzufügen musste, um es zu verwenden. Danke für die Korrektur. Ihr Zusatz (Umbenennen in eine Zip-Datei und Lesen der XML-Datei) ist genial. Ich hatte keine Ahnung, dass das funktionieren würde. Dies ist bislang die einzige Methode, mit der die Blätter in der angegebenen Reihenfolge angezeigt werden, ohne COM zu verwenden. +1!
Sid Holland

1

Das hat bei mir funktioniert. Von hier gestohlen: Wie erhält man den Namen der ersten Seite einer Excel-Arbeitsmappe?

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;

2
Hallo. Ich bin froh, dass Sie Arbeitscode haben, aber dieser verwendet die Interop-Klassen und sie funktionieren auf einem Server nicht zuverlässig. Sie können diesen Code beispielsweise nicht unter Windows Server 2008 ausführen. Sie können ihn also nicht in einer Web-App oder in serverseitigem Code verwenden. Deshalb habe ich mich für oledb entschieden und nicht für Interop.
Steve Cooper

1

Versuche dies. Hier ist der Code, um die Blattnamen in der richtigen Reihenfolge zu erhalten.

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;
}

Ist nicht mal compilierfähig! (Zeile Excel.XlFileFormat.xlWorkbookNormal)
Michael Hutter

0

Gemäß MSDN funktioniert dies bei Tabellenkalkulationen in Excel möglicherweise nicht, da Excel-Dateien keine echten Datenbanken sind. Daher können Sie den Blattnamen nicht in der Reihenfolge seiner Visualisierung in der Arbeitsmappe abrufen.

Code zum Abrufen des Blattnamens gemäß ihrem visuellen Erscheinungsbild mithilfe von Interop:

Verweis auf Microsoft Excel 12.0-Objektbibliothek hinzufügen.

Der folgende Code gibt den Blattnamen in der tatsächlichen Reihenfolge an, die in der Arbeitsmappe gespeichert ist, nicht den sortierten Namen.

Beispielcode:

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

0

Ich sehe keine Dokumentation, die besagt, dass die Reihenfolge in app.xml garantiert der Reihenfolge der Blätter entspricht. Es ist wahrscheinlich, aber nicht gemäß der OOXML-Spezifikation.

Die Datei workbook.xml enthält andererseits das Attribut sheetId, das die Reihenfolge bestimmt - von 1 bis zur Anzahl der Blätter. Dies entspricht der OOXML-Spezifikation. workbook.xml wird als der Ort beschrieben, an dem die Reihenfolge der Blätter beibehalten wird.

Daher wäre es meine Empfehlung, workbook.xml zu lesen, nachdem es aus dem XLSX extrahiert wurde. NICHT app.xml. Verwenden Sie anstelle von docProps / app.xml xl / workbook.xml und sehen Sie sich das Element wie hier gezeigt an.

`

<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>

`

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.