#c# #.net #excel #office-interop
#c# #.net #excel #office-interop
Вопрос:
Мне нужно получить данные из файла Excel, чтобы распечатать их в HTML-таблице (используя MVC, без gridview) и в конечном итоге сохранить их в базе данных.
Сопоставление между table и Excel выглядит следующим образом:
Excel -> Таблица
Первая строка -> Заголовки таблицы
Другие ячейки -> Табличные данные
Я использую Interop.Библиотека Excel, предоставляющая методы для работы с файлами Excel в .NET.
С помощью этого кода я получаю в переменной lworkSheet N-й лист файла Excel:
var lworkSheet = xlWorkBook.Worksheets.get_Item(N);
Давайте предположим, что файл Excel содержит только один лист (N = 1), я могу использовать специфические свойства листа для получения строк, столбцов, ячеек и диапазона. Эти свойства возвращают объекты типа Interop.Excel.Диапазон.
Проблема в том, что строки, столбцы и ячейки возвращают, соответственно, все строки, столбцы и ячейки в файле Excel, а не только те, которые заполнены данными. Поэтому, чтобы получить данные, которые я делаю (индекс элементов Excel основан на 1):
var lheaders = xlWorkSheet.Rows.get_Item(1);
var lexcelItems = new Excel.Range[xlWorkSheet.Rows.Count, xlWorkSheet.Columns.Count];
for (var i=0; i < xlWorkSheet.Rows.Count; i )
{
for(var j=0; j < xlWorkSheet.Columns.Count; j )
{
lexcelItems[i,j] = xlWorkSheet.Cells.get_Item(i 2, j 1);
}
}
Помимо вычислительных затрат на циклирование всех строк и столбцов, это решение по-прежнему неприемлемо, поскольку метод get_Item() возвращает объекты диапазона!! Чтобы получить элемент в ячейке, я должен использовать метод get_Range(cell_start, cell_end) и указать ячейки в формате «A1», «A2» и т.д. …
ВОПРОСЫ:
1) Есть ли способ определить последний элемент в строке и столбце?
2) Есть ли способ получить значение в ячейке без указания диапазона?
3) Любая библиотека, которая реализует Excel.Увеличение диапазона? (т.Е. (A1 ) == A2 и т.д.).
4) Если ничего из вышеперечисленного не выполнимо, есть ли простой способ прочитать Excel с помощью OLEDB?
Спасибо
Франческо
Ответ №1:
Я не работал с этой библиотекой, поэтому я просто делаю обоснованное предположение из документации MSDN. Вы ищете Worksheet.UsedRange
?
После того, как у вас есть Range
, похоже, что вы можете использовать Range.Cells
свойство (аналогичное используемому вами Worksheet.Cells
свойству), чтобы получить диапазон одной ячейки, а затем использовать свойство Range.Value
or Range.Value2
для получения значения этой ячейки:
Чтобы указать ячейки внутри UsedRange
на основе позиции, а не имен строк / столбцов, используйте Range.Offset
:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range (v =office.11).aspx
Комментарии:
1. да, это может быть полезно, спасибо. Однако это не решает проблему работы с объектами диапазона. Как бы вы извлекли фактические значения из Excel?
2. Что ж, если вы используете свойства Value и Value2, вам все равно нужно указать диапазон: Range(«a1»).Value, чтобы получить значение в ячейке A1. Моя проблема в том, что я не могу выполнять цикл, если мне каждый раз приходится определять, как увеличивать столбцы на букву алфавита. Проблема возникает, когда после z приходится использовать 2 буквы (от AA до ZZ), затем 3 (от AAA до ZZZ) и так далее.
Ответ №2:
Использование OLEDB для доступа / обработки данных Excel лучше, чем перебор.Cells(); помещение (выбора) листа с одним оператором SQL в таблицу базы данных или .getString результирующий набор в виде HTML-таблицы без каких-либо Fors является привлекательным.
Проблема: если ваши данные содержат мусор, высокоуровневые средства ADO / OLEDB не дадут вам возможности вмешаться.
ДОБАВЛЕНО:
Проводя некоторые эксперименты с тем, что означает «все» для листа Excel, я наткнулся на интересный факт? о «$». Возможно, я не единственный, кто не знает об этом:
Это результат моего тестового скрипта VBScript:
-------------------------------------------------------------------------------
SELECT * FROM [SakAct$]
-------------------------------------------------------------------------------
|actor_id|first_name|last_name|last_update |
| 3|ED |CHASE |2/15/2006 4:34:33 AM|
| 4|JENNIFER |DAVIS |2/15/2006 4:34:33 AM|
| 1|PENELOPE |GUINESS |2/15/2006 4:34:33 AM|
| 2|NICK |WAHLBERG |2/15/2006 4:34:33 AM|
| <NULL>|ED |CHASE |2/15/2006 4:34:33 AM|
| 5| |DAVIS |2/15/2006 4:34:33 AM|
| 6|PENELOPE | |2/15/2006 4:34:33 AM|
| 7|NICK |WAHLBERG | <NULL> |
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
SELECT * FROM [SakAct]
-------------------------------------------------------------------------------
|actor_id|first_name|last_name|last_update |
| 3|ED |CHASE |2/15/2006 4:34:33 AM|
| 4|JENNIFER |DAVIS |2/15/2006 4:34:33 AM|
| 1|PENELOPE |GUINESS |2/15/2006 4:34:33 AM|
| 2|NICK |WAHLBERG |2/15/2006 4:34:33 AM|
-------------------------------------------------------------------------------
Похоже, что [Sheet $] включает режим Excel Quirks, который будет учитывать больше строк, чем более строгий подход, поддерживаемый [Sheet].
Комментарии:
1. Спасибо за ваш ответ. Как бы вы, например, получили фактически используемые ячейки с рабочего листа? А первая строка?
2. @Francesco: Если вы выполните команду «ВЫБРАТЬ * ИЗ Sheet1 $», вы получите «все» строки. «Все» определяется поставщиком; вы можете не соглашаться. Но для получения приличных данных у меня никогда не было причин жаловаться. Что касается первой строки: коллекция полей возвращаемого набора записей предоставляет вам имена и типы полей.
3. Хорошо, я понимаю выражение, но откуда вы берете «Sheet1 $»? Что это за объект?
4. «Sheet1» — это имя листа; оно функционирует как имя таблицы в стандартном SQL; $ может потребоваться, а может и не понадобиться, в зависимости от поставщика.