SİPARİŞTE sayfa adlarını almak için Excel OleDb kullanma


103

OleDb'yi birçok sayfa içeren bir excel çalışma kitabından okumak için kullanıyorum.

Sayfa adlarını okumam gerekiyor, ancak elektronik tabloda tanımlandıkları sırayla onlara ihtiyacım var; bu yüzden buna benzeyen bir dosyam varsa;

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

O zaman sözlüğe ihtiyacım var

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

Kullanmayı denedim OleDbConnection.GetOleDbSchemaTable()ve bu bana isimlerin listesini veriyor ama alfabetik olarak sıralıyor. Alfa sıralaması, belirli bir adın hangi sayfa numarasına karşılık geldiğini bilmediğim anlamına gelir. Böylece anlıyorum;

GERMANY, IRELAND, UK

ki sırasını değişti UKve IRELAND.

Sıralanmasını istememin nedeni, kullanıcının ada veya dizine göre bir dizi veri seçmesine izin vermem gerekmesidir; 'ALMANYA'dan İRLANDA'ya kadar tüm verileri' veya 'sayfa 1'den sayfa 3'e kadar olan verileri' isteyebilirler.

Herhangi bir fikir çok takdir edilecektir.

ofiste birlikte çalışma sınıflarını kullanabilirsem, bu çok kolay olurdu. Ne yazık ki, birlikte çalışma sınıfları Windows hizmetleri ve ASP.NET siteleri gibi etkileşimli olmayan ortamlarda güvenilir şekilde çalışmadığı için yapamıyorum, bu yüzden OLEDB kullanmam gerekiyordu.


Excel dosyasının hangi sürümünü okuyorsunuz?
Yamen

30
vay, bunu nasıl
çizdin

4
@ АртёмЦарионов - tablo için dikey çubuklar (|) ve alt çizgiler (_) ve sekmeler için geriye ve ileriye doğru eğik çizgiler (\ /) satırlarıdır. Bir metin düzenleyiciye kopyalayın ve göreceksiniz.
Sid Holland

Yanıtlar:


17

Bunu gerçek MSDN belgelerinde bulamıyorum, ancak forumlardaki bir moderatör şunu söyledi:

OLEDB'nin sayfa sırasını Excel'de olduğu gibi korumadığından korkuyorum

Çalışma Sayfası Sırasına Göre Excel Sayfa Adları

Görünüşe göre bu, iyi bir geçici çözüm olması için yeterince yaygın bir gereksinim olacak.


Ancak bu doğrudan cevap verdi, gereksiz denemelerde çok zaman kazandırdı.
Shihe Zhang

75

0'dan İsim sayısı -1'e kadar sayfalarda döngü yapamaz mısınız? bu şekilde onları doğru sırayla almalısınız.

Düzenle

Yorumlar aracılığıyla, sayfa adlarını almak için Interop sınıflarını kullanmakla ilgili pek çok endişe olduğunu fark ettim. Bu nedenle, bunları almak için OLEDB kullanan bir örnek:

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

Çıkarılan Madde CodeProject üzerinde.


Bu görmek istediğim kod! N'inci sayfayı ve sayfa sayısını nasıl sorgulayabilirsiniz?
Steve Cooper

13
Merhaba James. Bu hemen hemen benim orijinal sorunum - GetOleDbSchemaTable () yöntemi adları alırken, satır numarası çalışma kitabı sayfa numarasına karşılık gelmiyor. Yani Sayfa 4, alfabede önce gelirse, sıra 0 olurdu.
Steve Cooper 05

23
Posterler sorusuna cevap vermiyor (Excel'de
Andrew White

7
@Samuel OP'nin problemini doğrudan çözdüğünü sanmıyorum, ancak benzer bir sorunla pek çok kişiye yardımcı olmuş gibi görünüyor.
James

1
OP'nin sorusunu çözmüyor, aradığım şey buydu. (Her zaman olumsuz oylama nedenini bildiririm.)
Phil Nicholas

23

Yukarıdaki kod, Excel 2007 için sayfa adı listesini çıkarma prosedürlerini kapsamadığından, aşağıdaki kod hem Excel (97-2003) hem de Excel 2007 için de geçerli olacaktır:

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

Yukarıdaki fonksiyon, her iki excel türü için (97,2003,2007) özellikle excel dosyası olmak üzere sayfanın listesini döndürür.


11
Bu kod, sayfaları Excel'de göründükleri sırayla döndürmez
Andrew White

11

Bu kısa, hızlı, güvenli ve kullanılabilir ...

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

"Kutudan çıkar çıkmaz" çalışmaz. exceladdress- bu nedir?
Michael Hutter

8

Diğer yol:

xls (x) dosyası, bir * .zip kapsayıcısında depolanan * .xml dosyalarının bir koleksiyonudur. docProps klasöründeki "app.xml" dosyasını açın.

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

Dosya bir Alman dosyasıdır (Arbeitsblätter = çalışma sayfaları). Tablo adları (Tabelle3 vb.) Doğru sıradadır. Sadece bu etiketleri okumanız gerekiyor;)

Saygılarımızla


1
Bu, xlsx dosyaları için iyi çalışır, ancak xls dosyaları için uygun değildir. Aynı yapıya sahip değiller. Aynı verilerin bir xls dosyasından nasıl çıkarılabileceğini biliyor musunuz?
rdans

6

@Kraeppy ( https://stackoverflow.com/a/19930386/2617732 ) yanıtında verilen bilgileri kullanarak aşağıdaki işlevi oluşturdum . Bu, .net çerçevesi v4.5'in kullanılmasını ve System.IO.Compression'a bir başvuru gerektirir. Bu yalnızca xlsx dosyaları için çalışır, eski xls dosyaları için geçerli değildir.

    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

Sayfaları 1_Germany, 2_UK, 3_IRELAND olarak adlandırmak için @ ölümApril fikrini seviyorum. Yüzlerce sayfa için bu yeniden adlandırmayı yapma sorununuzu da aldım. Sayfa adını yeniden adlandırmakla ilgili bir sorununuz yoksa, bunu sizin yerinize yapmak için bu makroyu kullanabilirsiniz. Tüm sayfa adlarının yeniden adlandırılması saniyeden az sürecektir. ne yazık ki ODBC, OLEDB sayfa adı sırasını artan ile döndürür. Bunun yerini hiçbir şey tutamaz. Sırada olması için COM kullanmalı veya adınızı yeniden adlandırmalısınız.

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

GÜNCELLEME: BIFF ile ilgili @SidHoland yorumunu okuduktan sonra bir fikir parladı. Aşağıdaki adımlar kod aracılığıyla yapılabilir. Sayfa adlarını aynı sırayla almak için bunu gerçekten yapmak isteyip istemediğinizi bilmiyorum. Bunu kod aracılığıyla yapmak için yardıma ihtiyacınız olursa bana bildirin.

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

GÜNCELLEME: Başka bir çözüm - NPOI burada yardımcı olabilir 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();

Bu çözüm xls için çalışıyor. Xlsx'i denemedim.

Teşekkürler,

Esen


1
Sen yok olması sayfaları yeniden adlandırmak veya cevabım DAO kullanabilirsiniz gösterdiği gibi, sadece, COM kullanmak. BIFF'yi okuyarak onları geri almanın da bir yolu olabileceğini düşünüyorum , ancak hala bunu araştırıyorum.
Sid Holland

1
@SidHolland: DAO bir COM bileşenidir. COM bileşenini Server 2008'de kullanmak bir sorundur, bu nedenle Steve ADO.NET ile gitti
Esen

Beynim, DAO'nun bir COM bileşeni olduğunu, onu kullanmak için bir COM referansı olarak eklemek zorunda kalmasına rağmen, öyle düşünmedi. Düzeltme için teşekkürler. Eklemeniz (bir zip olarak yeniden adlandırmak ve XML'i okumak) dahice. Bunun işe yarayacağını bilmiyordum. Şimdiye kadar, sayfaları COM kullanmadan sırayla gösterecek tek yöntem budur. +1!
Sid Holland

1

Bu benim için çalıştı. Buradan çalındı: Bir Excel çalışma kitabının ilk sayfasının adını nasıl alırsınız?

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
Selam. Çalışan kodunuz olduğuna sevindim, ancak bu Interop sınıflarını kullanıyor ve bir sunucuda güvenilir şekilde çalışmıyorlar; bu kodu örneğin Windows Server 2008 üzerinde çalıştıramazsınız. Yani bir web uygulamasında veya sunucu tarafı kodunda kullanamazsınız. Bu yüzden Interop yerine oledb için gidiyordum.
Steve Cooper

1

Bunu dene. İşte sayfa adlarını sırayla almak için kod.

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

MSDN'ye göre, Excel'in içindeki elektronik tablolar durumunda, Excel dosyaları gerçek veritabanları olmadığından çalışmayabilir. Böylece, çalışma kitabındaki görselleştirme sırasına göre sayfaların adını alamayacaksınız.

Birlikte çalışmayı kullanarak görsel görünümlerine göre sayfaların adını almak için kod:

Microsoft Excel 12.0 Nesne Kitaplığı'na başvuru ekleyin.

Aşağıdaki kod, sayfaların adını sıralı adı değil, çalışma kitabında depolanan gerçek sırayla verecektir.

Basit kod:

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

App.xml'deki siparişin, sayfaların sırası olduğunu belirten herhangi bir belge görmüyorum. Muhtemelen öyledir, ancak OOXML spesifikasyonuna göre değildir.

Diğer yandan çalışma kitabı.xml dosyası, 1'den sayfa sayısına kadar sırayı belirleyen sheetId özniteliğini içerir. Bu, OOXML spesifikasyonuna göredir. çalışma kitabı.xml, sayfaların sırasının saklandığı yer olarak tanımlanır.

XLSX'ten çıkarıldıktan sonra workbook.xml'yi okumak benim tavsiyem olacaktır. App.xml DEĞİL. DocProps / app.xml yerine, xl / workbook.xml kullanın ve burada gösterildiği gibi öğeye bakın -

'

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

'

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.