Использование Excel OleDb для получения имен листов В ЛИСТЕ ЗАКАЗА

Я использую OleDb для чтения из книги Excel с большим количеством листов.

Мне нужно прочитать имена листов, но мне они нужны в том порядке, в котором они определены в электронной таблице; поэтому, если у меня есть файл, который выглядит следующим образом;

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

Тогда мне нужно получить словарь

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

Я пробовал использовать OleDbConnection.GetOleDbSchemaTable() , и это дает мне список имен, но в алфавитном порядке сортирует их. Альфа-сортировка означает, что я не знаю, какой номер листа соответствует определенному имени. Поэтому я получаю;

 GERMANY, IRELAND, UK 

который изменил порядок UK и IRELAND .

Причина, по которой мне нужно ее сортировать, заключается в том, что я должен позволить пользователю выбирать диапазон данных по имени или индексу; они могут запросить «все данные от ГЕРМАНИИ до ИРЛАНДИИ» или «данные от листа 1 до листа 3».

Любые идеи очень приветствуются.

если бы я мог использовать классы взаимодействия в офисе, это было бы просто. К сожалению, я не могу, потому что классы interop не работают надежно в неинтерактивных средах, таких как службы Windows и сайты ASP.NET, поэтому мне нужно было использовать OLEDB.

Не можете найти это в реальной документации MSDN, но модератор на форумах сказал

Я боюсь, что OLEDB не сохраняет порядок листов, как в Excel

Имена листов Excel в листе

Похоже, это было бы достаточно общим требованием, чтобы было достойное обходное решение.

Можете ли вы не просто прокручивать листы от 0 до Count of names -1? таким образом вы должны получить их в правильном порядке.

редактировать

Я заметил в комментариях, что существует много опасений по поводу использования классов 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.

Поскольку выше код не распространяется на процедуры для извлечения списка имени листа для 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(ie sheet name always ends with $ sign) { listSheet.Add(drSheet["TABLE_NAME"].ToString()); } } } return listSheet; } 

Выше функция возвращает список листов в определенном файле excel для обоих типов excel (97,2003,2007).

Другой путь:

Файл xls (x) – это всего лишь коллекция файлов * .xml, хранящихся в контейнере * .zip. распакуйте файл «app.xml» в папке 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> 

Файл является немецким файлом (Arbeitsblätter = worksheets). Названия таблиц (Tabelle3 и т. Д.) Находятся в правильном порядке. Вам просто нужно прочитать эти теги;)

С уважением

Я создал функцию ниже, используя информацию, предоставленную в ответ от @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); } } 

Мне нравится идея @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 

UPDATE: другое решение – 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.

Благодаря,

Эсен

Это сработало для меня. Украденный здесь: Как вы получаете имя первой страницы книги 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; 

Попробуй это. Вот код для получения имен листов по порядку.

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

Согласно 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); } 

Я не вижу никакой документации, в которой говорится, что порядок в app.xml гарантированно будет порядком листов. Это PROBABLY, но не в соответствии со спецификацией OOXML.

С другой стороны, файл workbook.xml включает атрибут sheetId, который определяет последовательность – от 1 до количества листов. Это соответствует спецификации OOXML. workbook.xml описывается как место, где сохраняется последовательность листов.

Поэтому чтение workbook.xml после его извлечения из XLSX будет моей рекомендацией. НЕ 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> 

`

  • System.Data.OleDb.OleDbException: неверный адрес в Интернете. Как подключиться к файлам excel, расположенным на веб-сервере, с помощью OleDb
  • Разные пользователи не могут одновременно использовать мое приложение WinForms
  • Чтение Excel 2.0 в datatable
  • Чтение файла excel с использованием поставщика данных OLEDB
  • Как SQL-запрос этой таблицы excel с акцентированными именами столбцов в заголовке?
  • Microsoft ACE OLE DB 12.0 не зарегистрирован на локальном компьютере. Но это
  • Запрос файла Excel с C #, вопрос с числовыми ячейками
  • C # Создание файла Excel - JET.OLEDB.4.0 и ACE.OLEDB.12.0 Вывод столбцов одинаковых данных в разных форматах дат
  • Является ли «Microsoft Office 2007 Primary Interop Assembly» тем же, что и «Драйвер системы Office 2007: компоненты подключения к данным»,
  • OleDbConnection открывает лист как доступный только для чтения в любом открытом окне Excel
  • Чтение файла Excel с помощью OLEDB?
  • Давайте будем гением компьютера.