Как исправить ошибку (парсим xls)?
Добрый день! Есть задача распарсить xls. Все вроде хорошо и не раз уже такое делал , пользуюсь библиотекой apache.poi .
Три строчки кода
И тут выпадает эксепшен:
«Exception in thread «main» java.lang.RuntimeException: Unexpected missing row when some rows already present»
Я примерно понимаю в что xls необычный и есть вырезанные ячейки, совмещенные ячейки/строки, но не понимаю как побороть данную ошибку.
- Вопрос задан более трёх лет назад
- 552 просмотра
ну а как обычно борят? Джава же данные не родит, если их там нет
отсеивайте проблемные строки, разбирайте вручную
Обычно . хм . наверное хияк-хияк )
А что значит проблемная строка ?
Полный эксепшен
Exception in thread «main» java.lang.RuntimeException: Unexpected missing row when some rows already present
at org.apache.poi.hssf.usermodel.HSSFSheet.setPropertiesFromSheet(HSSFSheet.java:211)
at org.apache.poi.hssf.usermodel.HSSFSheet.(HSSFSheet.java:136)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:355)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:400)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:381)
at odsPars.main(odsPars.java:10)
Он указывает что ошибка в этой строке
HSSFWorkbook xlsxFile = new HSSFWorkbook(new FileInputStream(«../отчет.xls»));
Источник
Ошибка во время парсинга excel файла что это значит
Itsys |
| ||
Эксперт Профиль Репутация: 1 Требуется импортировать данные из Excel файлов в таблицу MS SQL Надо сделать импорт в эту таблицу произвольного Excel файла (структура может меняться, т.е. набор и количество колонок не постоянно) определенных колонок, т.е. не все подряд, а только допустим 3, 4 и 12 в соответствующие колонки таблицы MS SQL, т.е. 3 колонка в Col3, 4 в Col4, 12 в Col12 и начиная с определенной строки, например с 20 и до конца. Все осложняется тем, что может быть задан произвольный фильтр парсинга, например 4 колонка больше 60, соответственно загружаются все строки, у которых значение в четвертой колонке больше 60, фильтров может быть несколько. Второе больше не усложнение, а условие — файл Excel находится на другом сервере в сети и доступен через шару. PS Данный механизм реализован на Perl, т.е. perl парсит Excel файл и с помошью запросов вставляет это в таблицу, но работает все это очень медлено файл Excel на 16000 строк и 20 колонок парсится около 1-2 минут. Загрузка процессора под 100%, весь отжирается памяти примерно вес файла *3 и загружается сеть, т.к. perl стоит там же, где лежит Excel — на другом сервере. Загрузку файла на 50000 строк, я так и не дождался — обрубил. ЗЫ Самый главный вопрос, если это реализовать средствами MS SQL, если это, конечно, впринципе возможно, будет ли это работать быстрее и меньше грузить процессор, память и сеть? | |||
|
Akina |
| ||
|
Magnifico |
| ||
Код |
Select * From Openrowset(‘msdasql’,’DRIVER= ‘Select * From [sheet1$]’) |
SharedNoob |
| ||
|
Itsys |
| |||||||
Эксперт Профиль Репутация: 1
Потому-что это используется в интернет-магазине, написанном на perl, а файл Excel — это прайсы поставщиков, которые загружаются, сверяются с существующими товарами поставщика, корректируются цены и д.р. параметры товаров в магазине и добавляются новые — нет возможности добавить в Excel доп обработчики, т.к. файлы не наши, и обяснять как это делать каждому менеджеру после получения файла, собственно говоря не хочется
У нас 2000 и пока никаких причин, чтобы покупать 2005 нет, хотя это может стать причиной, вопрос в скорости работы. насколько быстро данный запрос откроет файл на 10 мегов? Добавлено через 2 минуты и 2 секунды
Вообще не выход, т.к.
Какие колонки импортировать а какие нет — определяет менеджер при импорте, и файлы у всех поставщиков очень уж разные | ||||||||
|
Magnifico |
| ||
|
SharedNoob |
| ||||||
Цитата(Magnifico @ 13.3.2008, 14:04) |
для 2005 open rowset |
Код |
Select * From Openrowset(‘msdasql’,’DRIVER= ‘Select * From [sheet1$]’) |
Дык а чем не устраивает это ? возвращает набор данных который лежит в ексель файле . да дальше вороти-нехачу .
Добавлено @ 15:18
ой извеняюсь, недочитал . sql2005
ДЛЯ SQL 2000
вариант 1
Код |
SELECT * FROM OPENDATASOURCE( ‘Microsoft Excel Driver (*.xls)’, ‘Data Source=D:\ ;’ ). [название файлла без расширения] |
Код |
SELECT * FROM OPENROWSET (‘MSDASQL’, ‘Driver= SourceDB=d:\; DefaultDir=d:\; SourceType=XLS; Exclusive=No; BackgroundFetch=Yes; Collate=Russian; Null=No; Deleted=No;’, ‘SELECT * FROM [название файлла без расширения]’) |
код на работоспособность не проверял но с драйвером для DBF все пашет
Это сообщение отредактировал(а) SharedNoob — 13.3.2008, 15:27
Itsys |
| ||
Эксперт Профиль Репутация: 1 А DefaultDir можно задать как \\server\files\? Это сообщение отредактировал(а) Itsys — 13.3.2008, 15:42 | |||
|
SharedNoob |
| ||
|
Itsys |
| ||
Эксперт Профиль Репутация: 1
До этого я сам догадался . Спасибо что напомнил, что есть такая функция в MS SQL (шутка). Ладно протестирую сообщу результаты. Это сообщение отредактировал(а) Itsys — 13.3.2008, 16:09 | |||
|
Itsys |
| |||||
Эксперт Профиль Репутация: 1
Только парсит он не правильно
Почему некоторые значения изменены на NULL? | ||||||
|
Magnifico |
| ||
Код |
Sub ПривестиКСтроке() Dim temp As String Dim str As String str = «‘» For Each c In Selection temp = Trim(c.Value) |
c.Value = str & temp
Next c
End Sub
Itsys |
| ||
Эксперт Профиль Репутация: 1
Есть друие предложения и варианты? PS хотелось бы сделать все без вмешательства пользователей — получил файл по почте — загрузил в back-office интернет-магазина и все — дальше система сама все обрабатывет, менеджеру надо только подтверждать выполнение определнных действий.. | |||
|
Magnifico |
| ||
Код |
select [ЗДЕСЬ] from openrowset( ‘MSDASQL’, ‘Driver=Microsoft Excel Driver (*.xls);DBQ=\\pavlov\Files\34’, ‘SELECT [ИЛИ ЗДЕСЬ] FROM [LIST$]’ ) as xls |
если использовать эксель в качестве источника данных ADO ,OLE то полюбому будет приводится столбец к определенному типу данных
(которых больше в столбце) и будут ошибки преобразования.
Только банально перебирать столбцы и строки и приводить каждую ячейку к определн формату
для обработки грязных юзерских данных может и понадобится сложные обработчики писать и не в SQLSERVERE
да и ресурсоемкое это занятие
Itsys |
| ||
Эксперт Профиль Репутация: 1 Проблема только в том, что исходный файл произвольный, т.е. изначально не известно даже сколько колонок в файле, заголовки полей моут стоять в любой строке файла — моут в первой, а могут и в 20, так как в приведенном выше примере, и, первым делом чего я хочу сделать, так это получить хотябы список полей, а он мне вместо заголовка поля выдает NULL. Есть ли способ CASTить все поля запроса в VARCHAR без их конкретного указания, ну типа CAST(* AS VARCHAR(5000))? | |||
|
Beltar |
| ||
Опытный Профиль Репутация: нет | |||
|
Magnifico |
| ||
|
Magnifico |
| ||
Код |
select * from openrowset(‘Microsoft.Jet.OLEDB.4.0’ , ‘Excel 8.0; HDR=YES; IMEX=1;Database=C:\my.xls’ , [sheet1$]) |
Select *
FROM OPENDATASOURCE(‘Microsoft.Jet.OLEDB.4.0’, ‘Data Source=C:\my.xls;
Extended Properties=»Excel 8.0;HDR=Yes;»‘). [sheet1$]
Itsys |
| ||
Эксперт Профиль Репутация: 1 Beltar, Обработка на perl уже написана, толь проблема в том, что грузится очень долго, вот и ищу возможность быстрее обработать данные. | |||
|
Itsys |
| ||
Эксперт Профиль Репутация: 1 | |||
|
Magnifico |
| ||
Код |
Sub ПеребратьИменаЛистов() Dim XLSFile As String Dim i As Integer i = 1 XLSFile = «C:\files\namesw.xls» |
Dim ws As Worksheet
For Each ws In Worksheets
MsgBox «Имя » & i & » -го листа: » & ws.Name
Debug.Print «Имя » & i & » -го листа: » & ws.Name
i = i + 1
Next ws
End Sub
Itsys |
| |||
Эксперт Профиль Репутация: 1 Вопрос только в том, как это запустить, а потом еще и желательнов запрос передать. мне сами именя листов не нужны, мне надо выбирать данные из первого листа в файле, может можно это как-нибудь задать не перебирая с помощью VB файл?
| ||||
|
Magnifico |
| ||||
Цитата |
Вопрос только в том, как это запустить |
excel -> (alt + F11)(Редактор VB) — > insert ->module ->копироватьКодСюда ->правим пути в коде ->RUN
Ole automation это единственный способ добраться к свойствам и методам Эксель
Все языки программирования интегрируются с Эксель именно так, (и ничего другого кроме вышеприведенного кода не придумаешь)
Никаким запросом имена листов узнать невозможно
Эксель не база данных ,и нет возможности получить Информационную схему
Цитата |
желательно в запрос передать |
Если хочешь помучиться в 2000 есть расширенные хранимые процедуры на c++ (Visual Studio 6 )
(у меня на с++ «аллергия»)
В БОЛЕ набрать OLE Automation там есть какие то методы работы , можно вызывать VBA методы и св-ва (не разбирался)
ищи хороший пример
Или писать прогу на любом языке ,опять же интеграция с Эксель(код вверху)
подключение к sql server -> передача параметров из встроенного VBA в хранимую процедуру (с openrowsetoM)
Цитата |
мне надо выбирать данные из первого листа в файле |
Itsys |
| ||
Эксперт Профиль Репутация: 1 В общем решил я отказаться от этой затеи, т.к. срорее всего никакого убыстрения по сравнению с существующей обработкой на Perl я не получу. Еще раз спасибо. | |||
|
Magnifico |
| ||
Код |
declare @file_name varchar(255), @h_application int, @hr int,@h_workbook int , @data varchar(255),@source varchar(255),@description varchar(255) |
set @file_name = ‘c:\files\serge.xls’
exec @hr = sp_OACreate ‘Excel.Application’, @h_application OUT
exec @hr = sp_OAMethod @h_application, ‘Application.workbooks.Open’, @h_workbook OUT , @file_name
exec @hr = sp_OAGetProperty @h_application, ‘Workbooks(1).Sheets(1).Name’, @data OUT
SELECT @data as [dat]
exec sp_OAMethod @h_application, ‘Quit’
exec @hr=sp_OADestroy @h_application
—set @data =’NewSheet1′;
declare @SQL nvarchar(4000)
set @SQL =
‘SELECT * FROM OPENROWSET(»Microsoft.Jet.OLEDB.4.0»’ +’,’+»’Excel 8.0;HDR=Yes;IMEX=1;Database=C:\files\serge.xls»’+’,’+ »’Select * From [‘+ @data +’$]»)’
Itsys |
| ||
Эксперт Профиль Репутация: 1
set @file_name = ‘c:\files\serge.xls’ exec @hr = sp_OACreate ‘Excel.Application’, @h_application OUT exec @hr = sp_OAMethod @h_application, ‘Application.workbooks.Open’, @h_workbook OUT , @file_name SELECT @data as [dat] |
Насколько я понимаю, это все работает не очень быстро
Magnifico |
| ||||
Код |
exec @hr = sp_OAGetProperty @h_application, ‘Workbooks(1).Sheets(1).Name’, @data OUT |
я просто незнаю будет ли работать в 2000?
Что то ты рано сдался! Это то что доктор прописал .
Одна тонкость Workbooks(1).Sheets(1).Name -мы получаем имя первого листа первой открытой книги,если будет открыта другая книга,
допустим локально , а потом будет выполнен этот запрос -то подхватит именно эту книгу ,а
Код |
exec @hr = sp_OAMethod @h_application, ‘Application.workbooks.Open’, @h_workbook OUT , @file_name |
будет уже второй.
Из этого следует лучше обращаться к книге по имени (надюсь её название хотя бы известно или тоже скрипт писать ,перебирая все
эксель файлы? )
Код |
Workbooks(«Names.xls»).Sheets(1).Name |
в 2000 OLE Automation должно как то включаться (поиск)
Itsys |
| ||||||
Эксперт Профиль Репутация: 1
|