Menggunakan Excel OleDb untuk mendapatkan nama lembar DALAM ORDER LEMBAR


103

Saya menggunakan OleDb untuk membaca dari buku kerja excel dengan banyak lembar.

Saya perlu membaca nama sheet, tetapi saya membutuhkannya dalam urutan yang ditentukan dalam spreadsheet; jadi Jika saya memiliki file yang terlihat seperti ini;

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

Lalu aku perlu mendapatkan kamusnya

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

Saya sudah mencoba menggunakan OleDbConnection.GetOleDbSchemaTable(), dan itu memberi saya daftar nama, tetapi menurut abjad mereka mengurutkannya. Alfa-sort berarti saya tidak tahu nomor sheet mana yang sesuai dengan nama tertentu. Jadi saya mendapatkan;

GERMANY, IRELAND, UK

yang telah mengubah urutan UKdan IRELAND.

Alasan saya membutuhkannya untuk diurutkan adalah karena saya harus membiarkan pengguna memilih kisaran data berdasarkan nama atau indeks; mereka bisa menanyakan 'semua data dari JERMAN ke IRELAND' atau 'data dari sheet 1 sampai sheet 3'.

Ide apa pun akan sangat dihargai.

jika saya dapat menggunakan kelas interop kantor, ini akan sangat mudah. Sayangnya, saya tidak bisa karena kelas interop tidak bekerja dengan andal di lingkungan non-interaktif seperti layanan windows dan situs ASP.NET, jadi saya perlu menggunakan OLEDB.


Versi file Excel apa yang Anda baca?
yamen

30
wow bagaimana kamu menggambar itu dan bagaimana kamu memiliki kesabaran untuk menggambar itu
l --''''''... '' '' '' '' '' '30

4
@ АртёмЦарионов - mereka adalah barisan bar vertikal (|) dan garis bawah (_) untuk tabel, dan garis miring ke belakang dan ke depan (\ /) untuk tab. Salin ke editor teks dan Anda akan melihat.
Sid Holland

Jawaban:


17

Tidak dapat menemukan ini dalam dokumentasi MSDN yang sebenarnya, tetapi kata seorang moderator di forum

Saya khawatir OLEDB tidak mempertahankan urutan lembar seperti di Excel

Nama Lembar Excel dalam Urutan Lembar

Sepertinya ini akan menjadi persyaratan yang cukup umum sehingga akan ada solusi yang layak.


Namun ini menjawab secara langsung, ini menghemat banyak waktu untuk percobaan yang tidak perlu.
Shihe Zhang

75

Bisakah Anda tidak hanya mengulang lembar dari 0 ke Hitungan nama -1? dengan cara itu Anda harus memasukkannya dalam urutan yang benar.

Edit

Saya melihat melalui komentar bahwa ada banyak kekhawatiran tentang penggunaan kelas Interop untuk mengambil nama sheet. Oleh karena itu, berikut adalah contoh penggunaan OLEDB untuk mengambilnya:

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

Diambil dari Artikel di CodeProject.


Itu kode yang ingin saya lihat! Bagaimana Anda bisa menanyakan 'lembar ke-N' dan jumlah lembar?
Steve Cooper

13
Hai, James. Ini adalah masalah asli saya - sementara metode GetOleDbSchemaTable () mendapatkan nama, nomor baris tidak sesuai dengan nomor lembar buku kerja. Jadi Lembar 4 akan menjadi baris 0, jika itu muncul pertama kali dalam alfabet.
Steve Cooper

23
Tidak menjawab pertanyaan poster (dia menginginkannya dalam urutan tampilan di Excel)
Andrew White

7
@Samuel Saya tidak berpikir itu menyelesaikan masalah OP secara langsung, namun, tampaknya membantu banyak orang lain dengan masalah serupa.
Yakobus

1
Tidak menyelesaikan pertanyaan OP, itulah yang saya cari. (Saya selalu memposting alasan downvote.)
Phil Nicholas

23

Karena kode di atas tidak mencakup prosedur untuk mengekstrak daftar nama sheet untuk Excel 2007, kode berikut juga akan berlaku untuk Excel (97-2003) dan 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;
}

Fungsi di atas mengembalikan daftar lembar dalam file excel tertentu untuk kedua jenis excel (97,2003,2007).


11
Kode ini tidak mengembalikan lembaran sesuai urutan kemunculannya di Excel
Andrew White

10

Ini singkat, cepat, aman, dan dapat digunakan ...

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

Tidak bekerja "di luar kotak". exceladdress- apa ini?
Michael Hutter

8

Cara lain:

file xls (x) hanyalah kumpulan file * .xml yang disimpan dalam wadah * .zip. unzip file "app.xml" di folder 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>

File tersebut adalah file Jerman (Arbeitsblätter = lembar kerja). Nama tabel (Tabelle3 dll) berada dalam urutan yang benar. Anda hanya perlu membaca tag ini;)

salam


1
Ini berfungsi dengan baik untuk file xlsx tetapi tidak untuk file xls. Mereka tidak memiliki struktur yang sama. Tahukah Anda bagaimana data yang sama dapat diekstraksi dari file xls?
rdans

6

Saya telah membuat fungsi di bawah ini menggunakan informasi yang diberikan dalam jawaban dari @kraeppy ( https://stackoverflow.com/a/19930386/2617732 ). Ini membutuhkan .net framework v4.5 untuk digunakan dan membutuhkan referensi ke System.IO.Compression. Ini hanya berfungsi untuk file xlsx dan tidak untuk file xls yang lebih lama.

    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

Saya suka ide @deathApril untuk memberi nama sheet sebagai 1_Germany, 2_UK, 3_IRELAND. Saya juga mendapat masalah Anda untuk melakukan penggantian nama ini untuk ratusan lembar. Jika Anda tidak memiliki masalah untuk mengganti nama lembar maka Anda bisa menggunakan makro ini untuk melakukannya untuk Anda. Diperlukan waktu kurang dari detik untuk mengganti nama semua nama sheet. sayangnya ODBC, OLEDB mengembalikan urutan nama sheet dengan asc. Tidak ada pengganti untuk itu. Anda harus menggunakan COM atau mengganti nama Anda agar sesuai.

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

PEMBARUAN: Setelah membaca komentar @SidHoland tentang BIFF, sebuah ide muncul. Langkah-langkah berikut dapat dilakukan melalui kode. Tidak tahu apakah Anda benar-benar ingin melakukannya untuk mendapatkan nama sheet dalam urutan yang sama. Beri tahu saya jika Anda memerlukan bantuan untuk melakukan ini melalui kode.

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: Solusi lain - NPOI mungkin bisa membantu di sini 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();

Solusi ini berfungsi untuk xls. Saya tidak mencoba xlsx.

Terima kasih,

Esen


1
Anda tidak perlu mengganti nama lembar atau hanya menggunakan COM, karena jawaban saya menunjukkan Anda dapat menggunakan DAO. Saya pikir mungkin juga ada cara untuk mengambilnya dengan membaca BIFF , tapi saya masih menyelidikinya.
Sid Holland

1
@SidHolland: DAO adalah komponen COM. Menggunakan komponen COM di Server 2008 adalah masalah, maka Steve menggunakan ADO.NET
Esen

Otak saya tidak menyimpulkan bahwa DAO adalah komponen COM, meskipun harus menambahkannya sebagai referensi COM untuk menggunakannya. Terima kasih atas koreksinya. Penambahan Anda (mengganti nama menjadi zip dan membaca XML) adalah hal yang jenius. Saya tidak tahu itu akan berhasil. Sejauh ini, satu-satunya metode yang akan menampilkan lembaran secara berurutan tanpa menggunakan COM. +1!
Sid Holland

1

Ini berhasil untuk saya. Dicuri dari sini: Bagaimana Anda mendapatkan nama halaman pertama buku kerja excel?

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
Hai. Senang Anda memiliki kode yang berfungsi, tetapi itu menggunakan kelas Interop, dan mereka tidak bekerja dengan andal di server; Anda tidak dapat menjalankan kode ini pada, katakanlah, Windows Server 2008. Jadi, Anda tidak dapat menggunakannya dalam aplikasi web atau kode sisi server. Itulah mengapa saya memilih oledb, daripada Interop.
Steve Cooper

1

Coba ini. Berikut adalah kode untuk mendapatkan nama sheet secara berurutan.

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

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

0

Sesuai MSDN, Dalam kasus spreadsheet di dalam Excel, ini mungkin tidak berfungsi karena file Excel bukan database nyata. Jadi Anda tidak akan bisa mendapatkan nama lembar dalam urutan visualisasinya di buku kerja.

Kode untuk mendapatkan nama sheet sesuai tampilan visualnya menggunakan interop:

Tambahkan referensi ke Perpustakaan Objek Microsoft Excel 12.0.

Kode berikut akan memberikan nama lembar dalam urutan sebenarnya yang disimpan di buku kerja, bukan nama yang diurutkan.

Kode sampel:

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

Saya tidak melihat dokumentasi apa pun yang mengatakan pesanan di app.xml dijamin sebagai urutan lembar. MUNGKIN, tetapi tidak sesuai dengan spesifikasi OOXML.

File workbook.xml, di sisi lain, menyertakan atribut sheetId, yang menentukan urutannya - dari 1 hingga jumlah sheet. Ini sesuai dengan spesifikasi OOXML. workbook.xml dideskripsikan sebagai tempat penyimpanan urutan sheet.

Jadi membaca workbook.xml setelah diekstraksi dari XLSX akan menjadi rekomendasi saya. BUKAN app.xml. Daripada docProps / app.xml, gunakan xl / workbook.xml dan lihat elemennya, seperti yang ditunjukkan di sini -

`

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

`

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.