<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55
global $wpdb2;
global $failure;
global $file_hist;
///// echo '<H2><b>Старт загрузки</b></H2><br>';
$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
///// echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}
$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
///// echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}
/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
///// echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
///// echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist); ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7]; ////получаем размер файла
$m_mtime_file=$masiv_data_file[9]; ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file
///// echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
///// echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
///// echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);
if ($results)
{ foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));
////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
///// echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
///// echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}
////загружаем данные
$table='vin_history'; // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация // (путь от корня web-сервера)
$delim=';'; // Разделитель полей в CSV файле
$enclosed='"'; // Кавычки для содержимого полей
$escaped='\
Может быть текст функции раскрасить?
(1) Хорошая идея, твоя обработка замечательно справиться 🙂
Век живи — век учись… Даже не подозревал о возможности Область.Value.Выгрузить();
Область.Value — это ComSafeArray. О нем в конфигураторе довольно подробно написано + методы тоже имеются.
быстрая функция это ADO
Просто и со вкусом.
ADO не всегда можно. Например нельзя когда разного типа данные в одном столбце. Привоодятся к строке
(7) Попробуй еще протестить на скоростьhttp://infostart.ru/projects/3214/
(9) Дык а чего там тестить?
Только оптимальную реализацию алгоритмов работы с Compound объектами?
(9) На правах рекламы :)))
Ваша реализация, ИМХО, самая быстрая, хотя не тестил 🙂
(9) Болт. не самая быстрая
Код
Скрипт = Новый COMОбъект(«MSScriptControl.ScriptControl»);
Скрипт.language = «javascript»;
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
ИмяВК=»AddIn.ExcelEditor»;
Попытка
ПодключитьВнешнююКомпоненту(ИмяВК);
Исключение
Предупреждение(«Не удалось подключить компоненту » + ИмяВК);
КонецПопытки;
Попытка
Экзель = Новый(ИмяВК);
Исключение
Предупреждение(«Ошибка создания объекта внешней компоненты: » + ИмяВК);
КонецПопытки;
Если Экзель.ОткрытьФайл(«c:delado.xls») тогда
Если Экзель.ОткрытьЛист(1) тогда
КоличествоКолонок = Экзель.ПолучитьКоличествоКолонок();
КоличествоСтрок = Экзель.ПолучитьКоличествоСтрок();
Таблица = Новый ТаблицаЗначений;
Для Сч = 1 по КоличествоКолонок Цикл
Таблица.Колонки.Добавить(«Колонка»+Строка(Сч));
КонецЦикла;
Для Сч = 1 по КоличествоСтрок Цикл
СтрокаТЗ = Таблица.Добавить();
Для Сч1 = 1 по КоличествоКолонок Цикл
СтрокаТЗ[Сч1-1] = Экзель.ПолучитьЗначениеЯчейки(Сч, Сч1);
КонецЦикла;
КонецЦикла;
Экзель.Выполнено();
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
ОчиститьСообщения();
Сообщить(«Выполнение скрипта заняло: » + Строка(ВремяОкончания — ВремяНачала) + » мсек. «);
КонецЕсли;
КонецЕсли;
Результат
Выполнение скрипта заняло: 2125 мсек.
(12) А где
«Строк = 100;
Колонок = 100;»
?
(12) И как бы создание объектов стоит убрать из тестов, а оставить только чтение данных.
Это был тест чтения
Обработано строк: 8 колонок: 10000 итого ячеек; 80000
Тест записи
Выполнение скрипта заняло: 484 мсек.
КОД
Скрипт = Новый COMОбъект(«MSScriptControl.ScriptControl»);
Скрипт.language = «javascript»;
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
ИмяВК=»AddIn.ExcelEditor»;
Попытка
ПодключитьВнешнююКомпоненту(ИмяВК);
Исключение
Предупреждение(«Не удалось подключить компоненту » + ИмяВК);
КонецПопытки;
Попытка
Экзель = Новый(ИмяВК);
Исключение
Предупреждение(«Ошибка создания объекта внешней компоненты: » + ИмяВК);
КонецПопытки;
Если Экзель.ОткрытьФайл(«c:delado.xls») тогда
Если Экзель.ОткрытьЛист(2) тогда
Строк = 100;
Колонок = 100;
Для Сч = 1 по Строк Цикл
Для Сч1 = 1 по Колонок Цикл
Экзель.РедактироватьЗначениеЯчейки(0, 1, Сч*Сч1);
КонецЦикла;
КонецЦикла;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
ОчиститьСообщения();
Сообщить(«Выполнение скрипта заняло: » + Строка(ВремяОкончания — ВремяНачала) + » мсек. «);
Экзель.Выполнено();
КонецЕсли;
КонецЕсли;
Кстати параметры функции РедактироватьЗначениеЯчейки в документации не указаны 🙂
(15) Попытка/Исключение хорошо кушают милисекунды, кстати.
Создание объектов включил специально, чтобы увидеть скорость выполнения не именно операция ввода-вывода, а скорость импорта-экспорта
Коды тестов есть — дорабатывать и оптимизировать можно всегда 🙂
Ваш код кстати 🙂
(18) Пожертвовать скоростью с попыткой/исключение при открытии обработки можно… Важна скорость обработки многомегобайтных файлов.
Ок без Попытка-исключение
Чтение
Выполнение скрипта заняло: 2093 мсек.
Запись
Выполнение скрипта заняло: 469 мсек.
И попробуй сделать 80000 строк.
И попробуй сделать 3 колонки — число, строка и дата 😉
Просто самому интересны результаты.
Без создания объектов чисто операции I/O
ЧТЕНИЕ
wildhog
КОД
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Область = ЛистЭксель.Range(ЛистЭксель.Cells(1,1), ЛистЭксель.Cells(ВсегоСтрок,ВсегоКолонок));
Данные = Область.Value.Выгрузить();
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
результат
Выполнение скрипта заняло: 109 мсек.
Обработано строк: 8 колонок: 10000 итого ячеек; 80000
ADO
КОД
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
ТЗ = ADOUtils.ADORecordsetToValueTable(НаборДанных);
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Результат
Выполнение скрипта заняло: 359 мсек.
Обработано строк: 8 колонок: 10000 итого ячеек; 80000
Использовалась ВК GameWithFire
Душелов
КОД
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Для Сч = 1 по КоличествоСтрок Цикл
СтрокаТЗ = Таблица.Добавить();
Для Сч1 = 1 по КоличествоКолонок Цикл
СтрокаТЗ[Сч1-1] = Экзель.ПолучитьЗначениеЯчейки(Сч, Сч1);
КонецЦикла;
КонецЦикла;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Результат
Выполнение скрипта заняло: 1843 мсек.
ЗАПИСЬ
COMSAfeArray
КОД
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Лист.Range(Лист.Cells(1,1),Лист.cells(Строк,Колонок)).Value = Массив2;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Результат
Выполнение скрипта заняло: 47 мсек.
Построчно
КОД
Строк = 100;
Колонок = 100;
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Для Сч = 1 по Строк Цикл
Для Сч1 = 1 по Колонок Цикл
Лист.cells(Сч,Сч1).Value = сч1;
КонецЦикла;
КонецЦикла;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Результат
Выполнение скрипта заняло: 22500 мсек.
Душелов
КОД
Строк = 100;
Колонок = 100;
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Для Сч = 1 по Строк Цикл
Для Сч1 = 1 по Колонок Цикл
Экзель.РедактироватьЗначениеЯчейки(0, 1, Сч*Сч1);
КонецЦикла;
КонецЦикла;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Результат
Выполнение скрипта заняло: 219 мсек.
Кинь файлик мне 😉 Посмотрю, что да как… Что-то долго слишком.
(23) На счет чтение… Там везде ТЗ 1С-овское получается?
А то у автора:
«Данные = Область.Value.Выгрузить();
Для Счетчик = 0 По ВсегоКолонок-1 Цикл
ТЗ.ЗагрузитьКолонку(Данные[Счетчик], Счетчик);
КонецЦикла;»
Как бы не объективно получается 😉
(19) согласен
я думал твоя вк будет самой быстрой, но видишь как получилось..
Думаю косяк в многократном вызове метода ВК РедактироватьЗначениеЯчейки, а там по цепочке callAsproc, callasfunc затем у тебя создание объекта типа cell и тд
(22)
Сегодня уже не смогу протестить с разными параметрами
(24) какой файлик? Excel? или тесты? или то и другое? мыло?
И на счет записи тоже самое. Приведи запись из 1С-овского ТЗ в 1 варианте.
(26) Эти тесты пока не объективны 😉
(27)
Эксель = Новый COMОбъект(«Excel.Application»);
Книга = Эксель.Workbooks.Add(«c:delado.xls»);
Лист = Книга.Sheets(2);
Скрипт = Новый COMОбъект(«MSScriptControl.ScriptControl»);
Скрипт.language = «javascript»;
//ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Строк = 100;
Колонок = 100;
Массив = Новый Массив(Строк,Колонок);
Для Сч = 0 по Строк — 1 Цикл
Для Сч1 = 0 по Колонок — 1 Цикл
Массив[сч][сч1] = сч1;
КонецЦикла;
КонецЦикла;
Массив2 = Новый COMSafeArray(Массив, «VT_I4»,Строк,Колонок);
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Лист.Range(Лист.Cells(1,1),Лист.cells(Строк,Колонок)).Value = Массив2;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Сообщить(«Выполнение скрипта заняло: » + Строка(ВремяОкончания — ВремяНачала) + » мсек. «);
Эксель.Visible = 1;
Вот из ComSafeArray/ надо из Тз — засунь ТЗ в массив и выведи
Согласен, что не все 1С-совское, но согласись, мы замеряем не скорость работы какого-то определенного интерфейса, а скорость операции импорта-экспорта
(24)
А ты реализцй у с(27)
Эксель = Новый COMОбъект(«Excel.Application»);
Книга = Эксель.Workbooks.Add(«c:delado.xls»);
Лист = Книга.Sheets(2);
Скрипт = Новый COMОбъект(«MSScriptControl.ScriptControl»);
Скрипт.language = «javascript»;
//ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Строк = 100;
Колонок = 100;
Массив = Новый Массив(Строк,Колонок);
Для Сч = 0 по Строк — 1 Цикл
Для Сч1 = 0 по Колонок — 1 Цикл
Массив[сч][сч1] = сч1;
КонецЦикла;
КонецЦикла;
Массив2 = Новый COMSafeArray(Массив, «VT_I4»,Строк,Колонок);
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Лист.Range(Лист.Cells(1,1),Лист.cells(Строк,Колонок)).Value = Массив2;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Сообщить(«Выполнение скрипта заняло: » + Строка(ВремяОкончания — ВремяНачала) + » мсек. «);
Эксель.Visible = 1;
Вот из ComSafeArray/ надо из Тз — засунь ТЗ в массив и выведи
Согласен, что не все 1С-совское, но согласись, мы замеряем не скорость работы какого-то определенного интерфейса, а скорость операции импорта-экспорта
Ты реализуй в своей вк метод типа ТЗВЭкзель 🙂
Решил и я потестировать оба варианта.
Методика тестирования.
Создал 3 файла, в каждом 6 колонок, строк в 1м файле — 12000, 2м ~ 24000, 3м ~ 49000.
1 тест. запуск последовательно (сначала COMSAFEARRAY, потом ADO) на чтение одного файла. После каждого чтения перезагрузка.
Результат.
Колонок: 6 Строк: 11 999
Выполнение скрипта заняло: 5 323 мсек.
Выполнение скрипта заняло: 2 880 мсек.
Колонок: 6 Строк: 24 661
Выполнение скрипта заняло: 7 061 мсек.
Выполнение скрипта заняло: 5 551 мсек.
Колонок: 6 Строк: 49 321
Выполнение скрипта заняло: 7 890 мсек.
Выполнение скрипта заняло: 10 335 мсек.
Видно, что увеличение количества строк сильно сказывается при чтении через ADO
2 тест. Чтение последовательно 3х файлов разными методами (сначала COMSAFEARRAY, потом ADO). После каждого чтения перезагрузка.
Закешировал создаваемые процедурами Com объекты.
Результат.
Выполнение скрипта заняло: 3 067 мсек.
Обработано строк: 6 колонок: 11 999 итого ячеек; 71 994
Выполнение скрипта заняло: 1 182 мсек.
Обработано строк: 6 колонок: 24 661 итого ячеек; 147 966
Выполнение скрипта заняло: 2 274 мсек.
Обработано строк: 6 колонок: 49 321 итого ячеек; 295 926
Выполнение скрипта заняло: 2 450 мсек.
Обработано строк: 6 колонок: 11 998 итого ячеек; 71 988
Выполнение скрипта заняло: 4 917 мсек.
Обработано строк: 6 колонок: 24 660 итого ячеек; 147 960
Выполнение скрипта заняло: 9 849 мсек.
Обработано строк: 6 колонок: 49 320 итого ячеек; 295 920
Для метода чтения через COMSAFEARRAY замерил время создания Com объекта Екселя. Время создания COM Excel :2 001 мсек.
3 тест. Собственно и не тест а замер производительности средствами 1С.
Результат.
При чтении через ADO больше всего времени занимает выполнение вот этой строки (70%):
СтрокаТЗ[«Колонка»+Строка(Сч)] = НаборДанных.Fields.Item(Сч-1).Value;
Обработка всего цикла считывания записей из recordset занимает 80% общего времени.
При чтении через COMSAFEARRAY 27% времени уходит на открытие файла.
27% на Данные = Область.Value.Выгрузить();
10% на ТЗ.Добавить(); 🙂
(25)
Здесь
Данные = Область.Value.Выгрузить();
«Данные» — тип ComSafeArray.
«ТЗ» — Тип таблица значений (самая что нинаеть 1совская 🙂 )
Чуть выше ж есть «ТЗ = Новый ТаблицаЗначений;»
А вот Данные[Счетчик] — уже типа МАССИВ. Он то легко и загружается методом
таблицы значений «ЗагрузитьКолонку».
(22) Если нужно прочитать данные сохранив именно те типы которые определены в Экселе, то в сабже нужно сформировать колонки таблицы значений заранее, указав соответствующие типы. В этом случае значения в результирующей ТЗ будут приводиться к типу колонки ТЗ.
Попробуйте затестить еще на 70000 строках 😉
(29) >Согласен, что не все 1С-совское, но согласись, мы замеряем не скорость работы какого-то определенного интерфейса, а скорость операции импорта-экспорта
>Вот из ComSafeArray/ надо из Тз — засунь ТЗ в массив и выведи
Это надо учитывать в подсчете времени теста!
Условия задачи надо определить жестче:
1) Из экзеля загрузить в ТЗ данные.
2) Из ТЗ записать данные в экзелевский файл.
(31) Да я знаю, я говорю автору теста kadr, о том, что тесты не объективны, т.к. у него в тестах отсутствует заполнение ТЗ, которое так же занимает время.
(34) как же отсутствует?
посмотри начальные тесты (7) там все есть…
затем я просто выложил голое время без создания, инициализации и заполнения объектов
(34) а как сделать 70000 строк? у мну получилось только 65536?
(35) я про (23), в моем примере ты заполняешь строку ТЗ.
(36) Сделай в 8-ке и сохрани в экзель 😉
(37) согласен
исправим первый пример с учетом загрузки ТЗ оптом
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Область = ЛистЭксель.Range(ЛистЭксель.Cells(1,1), ЛистЭксель.Cells(ВсегоСтрок,ВсегоКолонок));
Данные = Область.Value.Выгрузить();
Для Счетчик = 0 По ВсегоКолонок-1 Цикл
ТЗ.ЗагрузитьКолонку(Данные[Счетчик], Счетчик);
КонецЦикла;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Выполнение скрипта заняло: 141 мсек.
Обработано строк: 8 колонок: 10000 итого ячеек; 80000
И построчно
ВремяНачала = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Область = ЛистЭксель.Range(ЛистЭксель.Cells(1,1), ЛистЭксель.Cells(ВсегоСтрок,ВсегоКолонок));
Данные = Область.Value.Выгрузить();
Для Сч = 1 По ВсегоКолонок Цикл
Для Сч1 = 1 По ВсегоСтрок Цикл
ТЗ[Сч1-1][Сч-1] = Данные[Сч-1][Сч1-1];
КонецЦикла;
КонецЦикла;
ВремяОкончания = Формат(Скрипт.eval(«new Date().getTime()»),»ЧГ=0″);
Выполнение скрипта заняло: 828 мсек.
Обработано строк: 8 колонок: 10000 итого ячеек; 80000
(38) попробовал… алгоритм взял из (29).
Что-то мне подсказывало что ничего не получиться 🙂 . Так и вышло…
(40) Это один из главных минусол ОЛЕ екзеля, ниже 2007 версии 😉
(39) 🙂 Сейчас я поколдую с массивами, ибо компонента должна была работать и в 7-ке, а она (до не давнего времени) с комсэйф-массивами не работала, и можно будет протестировать.
(40)
http://excelsecrets.ru/post_1230987214.html
Непроверенные данные
(41) млин туплю. Работал с файлами xls а не xlsx… Офис у мну 2007.
Все нормально создалось ну и загрузилось соответственно.
(44) Результаты тестов какие?
(39) Ради эксперимента, попробуй в рег.бат компоненты моей после строки
regasm.exe ExcelEditor.dll /codebase
добавить строку
ngen.exe ExcelEditor.dll
и перерегить.
(44) xlsx уже не объективно 😉 формат другой. С ним можно протестить ради экспериментаhttp://infostart.ru/projects/3495/
(47, 45) для xlsx
Выполнение скрипта заняло: 13 240 мсек.
Обработано строк: 6 колонок: 123 301 итого ячеек; 739 806
Тут файл замера производительностиhttp://slil.ru/27691047
(47) Если честно. так и не вкурил как создать файл XLS с количеством строк более 65536. Выложи куда нить готовый файл протестирую.
(48) А по ссылке в (47) время замера можешь сделать?
(49) Сделай отчет в 1С-ке и сохранить табличный документ в экзель.
(50) Попробую.
Поделюсь еще мыслями. Вспомнил что у recorseta есть метод GetRows()
http://support.microsoft.com/kb/246335
Тут нашел полное описание
Но, оказалось, что получаемый массив нужно еще транспонировать, что скорее всего очень долго (м.б попозже попробую реализовать). Имхо этот метод (getrows)
не принесет ощутимого прироста в скорости, хотя, все возможно. 🙂
(51) В моем компоненте аналогичное добавил. Обновление залил.
Но, думаю, тоже не сильно прироста скорости будет… Хотя кто знает… Протестить надо. Метод «ПолучитьЗначения».
Замер производительности по (47) —http://slil.ru/27691324
Количество строк: 123 301
Количество колонок: 6
(53) А времени сколько вышло?
А файл для какого приложения? У меня ничего не стоит с этим расширением ассоциированного…
(54) Время в замере. Отдельно замерял. Но счет шел на минуты.
http://infostart.ru/projects/3495/
Файл xlsx.
Тестировал обработку чтения файла екселя средствами 1С которая из (47)
Функция взял из readme.
(55) Ну если на минуты, то тогда не надо 🙂
щас пробую ВК…
(46) чтение чуть быстрее стало
Выполнение скрипта заняло: 1735 мсек.
(56) Итак. Тест твоей компоненты.
Выполнение скрипта заняло: 6 621 мсек.
Обработано колонок : 7
Обработано строк : 64 299
Тот же файл, только по сабжу:
Выполнение скрипта заняло: 7 989 мсек.
Обработано строк: 7 колонок: 64 299 итого ячеек; 450 093
Опять же повторное чтение с помощью сабжа (сразу после первого):
Выполнение скрипта заняло: 3 997 мсек.
Обработано строк: 7 колонок: 64 299 итого ячеек; 450 093
Скажи. а в ВК используешь GetRows?
(59) + файл замера производительности.http://slil.ru/27691513
(59) Ну, примерно, аналогичное GetRows, но массив я все равно «ручками» заполняю.
И это ты тестил с «ПолучитьЗначения» ?
(61) Угу. пробежался по колонкам и загрузил данные
Экзель.ОткрытьФайл(ПутьКФайлу);
Экзель.ОткрытьЛист(1);
ВсегоКолонок = Экзель.ПолучитьКоличествоКолонок();
ВсегоСтрок = Экзель.ПолучитьКоличествоСтрок();
Для Счетчик = 1 По ВсегоСтрок Цикл
ТЗ.Добавить();
КонецЦикла;
Для Счетчик = 0 По ВсегоКолонок — 1 Цикл
Массив = Экзель.ПолучитьЗначения(Счетчик).Выгрузить();
ТЗ.ЗагрузитьКолонку(Массив, Счетчик);
КонецЦикла;
Пользую метод давно, хотел поделится, но никак не могу справиться с проблеммой, можт кто сталкивался?
Код: Файл = Новый COMОбъект(«Excel.Application»);
Файл.DisplayAlerts = 0; //не задавать вопросы
Файл.Application.AutomationSecurity = 3; //уровень безопасности
Книга = Файл.Workbooks.Open(ФайлХЛ);
Лист = Книга.Worksheets(2);
Пока (НЕ ПустаяСтрока(Строка(Лист.Cells(строкаXL,1).Value))) или
(НЕ ПустаяСтрока(Строка(Лист.Cells(строкаXL,2).Value))) Цикл
строкаXL = строкаXL+1;
КонецЦикла;
COMSafeArrayМассив = Лист.range(Лист.Cells(1,1),Лист.Cells(строкаXL,249)).Value;
Книга.Close();
Массив = COMSafeArrayМассив.Выгрузить();…………
Файл около 50 Мбайт с макросами и паролями(но с этим вроде разобрался), из одного листа файла загружаю 250 колонок * 6-10 000 строк, на строке Книга = Файл.Workbooks.Open(ФайлХЛ); висит 5-6 минут, остальное пролетает за секунды. Как можно это победить?
(63) А сколько времени открывается файл в WIndows?
попробуй отключать еще автопересчет формул, кажется свойство Calculation.
М.б еще какие макросы запускаются при открытии?
Если не поможет, м.б попробовать ADO? В этой ветке ado подробно осветили 🙂
сильно вы! респект! так на чем в итоге то останавливаемся?
(65) Я пользуюсь своей компонентой. И быстро, и без офиса. Т.к. у нас лицензионный софт везде, а офис не у всех стоит.
(66) млин((
написал чтение черед АДО. на работе работает. на домашнем компе тоже SP2 и
MDAC версии 2000.85.1022- не работает.
у того кому делал на висте -тоже не работает. у кого-то читает на висте через ADO
через компоненту твою я не умею..хотелось штатными (относительно) средствами.
(67) В чем проблема с компонентой?
АДО не работает как? Что пишет? Может поставщика данных нет в системе?
(68) компоненту не хочу, это слать клиенту длл, объяснять по телефону чё с ней делать..не. не хочу.
адо пишет «»BOF или EOF имеют значение True или текущая запись была удалена»»
(68) проблема локализовалась. в тестовых файлах было по 1му листу, и грузилось нормально, а в реале оказалось три листа в фале. пофиксил.
юзайте йоксель…
а адо как-то попробовал -и бросил ибо на первом же подсунутом файле читала половину файла и тупо финишировала как будто вконец данных — так победить и не смог…
Спасибо wilghog! 😀 Очень помогла статья. Эксель из 12600 строк загружается за 10 сек. Раньше загружаллось за 8 мин. Большое спасибо. 😀
Этот способ несомненно быстрее, но не совсем корректен и следовательно не универсален. Дело в том, что при выполнение Данные = Область.Value.Выгрузить() текст преобразуется, например у меня был артикул 0000056789 и он преобразуется в 56 789. А при стандартном (универсальном)по ячеестым обходом нет, когда вытаскиваешь из ячейки .text
Этот способ несомненно быстрее, но не совсем корректен и следовательно не универсален. Дело в том, что при выполнение Данные = Область.Value.Выгрузить() текст преобразуется, например у меня был артикул 0000056789 и он преобразуется в 56 789. А при стандартном (универсальном)по ячеестым обходом нет, когда вытаскиваешь из ячейки .text
Попробуй перед загрузкой создать колонки таблицы значений с указанием нужного типа. В этом случае при загрузке будет корректно выполнено приведение типов.
Спасибо, коротко и ясно=)
Спасибо за наВодку с методами Excel ) Всегда уважительно относился к емким и эффективным алгоритмам! Респект!
Эх, вот такую бы штуку для 7.7! Пробовала переписать — спотыкается о строку
Данные = Область.Value.Выгрузить();
говорит — «Ожидается скалярное выражение (Данные)».
Кто-нибудь знает, как научить семерку жрать массивы?
Сама загрузка в Таблицу значений действительно проходит махом, за это большое спасибо. Только рано я обрадовался. При дальнейшей обработки данных, для получения ссылочных данных все равно тормозит и обрабатывает долго. Строк около 5 тыс. НЕ подскажите, как убыстрить процесс? Ничего особенного не делаю, в цикле по таблице ищу номенклатуру и единицы измерения к ней.
redgoll
Проблема в том, что используешь либо запрос либо НайтиПо… в цикле. Что очень медленно…
Помещай ТЗ во временную таблицу и ищи элементы запросом через левое/внутреннее соединение с ней.
Не забудь, что для временнной таблицы важно чтобы колонки ТЗ были типизированы.
Спасибо, за совет. Попробую воспользоваться вашим методом. Потом отпишусь о результатах и поблагодарю отдельно. Когда-то читал на данном ресурсе про метод загрузки данных не из Excel, а из табличного документа (mxl). Автор помнится очень хвалил его за быстродействие. Не пробовали на такие грабли наступать?
(80)
Не пробовал. Но, думаю, что если и будет прирост в скорости, то не очень большой. + преобразование в mxl занимает время. Так что, смысла не вижу… Попробуйте, вдруг сабжевый способ не самый быстрый )
(82) Если дадите свою компоненту — погоняю, проверим.
А что на выходе 1Совская ТЗ или что-то еще?
У любого способа есть плюсы и минусы. У моего — универсальность, независимость от ВК (права пользователей, регистрация и т.д). У вашего скорость.
(85) Eugeneer, не стал писать про деньги )) Для многих это существенный минус…
Надеюсь продажи Вашей обработки говорят об обратном ))
Отличный метод. Автору большой плюс!
(82)
Здорово конечно, но приведенный автором статьи алгоритм + дополнение по записи от kadr полностью покрывает все проблемы — 0.4 сек на 80 000 ячеек.
В дальнейшем Вам стоит указывать и на это альтернативное решение
(74)
приведение типов происходит еще при выгрузке в массив Данные = Область.Value.Выгрузить(), к моменту заполнения таблицы значений артикул 0000056789 уже принимает следующий вид 56 789.
Какие еще есть идеи? Способ очень хорош, но вышеописанный момент все портит…
(91) добрый день. Пришлите файл, посмотрю. + попробуйте перед чтением типизировать колонки тз.
(92)
http://yadi.sk/d/21WzBuG5JSKpR
в том-то и дело, что до ТЗ не доходит, смотрю отладчиком массив Данные сразу после выгрузки в него области — там уже значения изменены…
Файл для примера:
(92)
Смотрю в вашем файле формат ячеек — то числовой (дополнительный), то числовой (все форматы), то общий (текстовой и числовой форматы, еще форматы)
Это ж ….
В принципе можно было бы отформатировать Область.NumberFormat=»Text»;
Но у Вас в ячейке визуально 00000141 — фактически в ячейке число 141, числовой формат дополнительный, греческий язык , тип «табельный номер» — который отображает 141 как 00000141 и далее аналогично
(93) По идее Область.Value берет именно ЗНАЧЕНИЯ ячеек, а не форматированные значения. В (94) все верно kiruha написал — проблемы в данных файла.
Поэтому, приводите в «нормальный» формат файл, а потом читайте.
В вашем случае, м.б рациональнее будет читать поячеечно — тогда сможете брать не значения ячеек, а их отформатированное значение. Проиграете в скорости, но выиграете в удобстве (не придется обрабатывать файл).
(94) kiruha,
Но при всем при этом, ЛистЭксель.Cells(СчетчикСтрок,СчетчикКолонок).Text возвращает именно 00000141 а не 141, как вы предполагаете!
(95)
так и сделал, читаю по старинке перебором ячеек. Жаль, но в данной реализации ваш метод далеко не универсален (предварительная обработка файла убивает все плюсы), хотя по скорости видимо лучший! Пойду на форум любителей экселя, может там что-то подскажут… В любом случае спасибо, идея отличная!
(97) Ну уж вы хотите и скорость и чтобы всякое повидло из файлов вытягивало. Удачи)
(98)
к сожалению боевые условия не всегда приближены к идеальным: как правило файлики для загрузки мы не сами себе стряпаем.
Еще есть способ — быстрой «вставки» таблицы из Excel в 1С — через копирование -вставку… (копипаст)
программным способом еще года 2 назад сам делал… через Wscript.Shell
«доработка» стандартной обработки загрузки из табличного документа
функция мПрочитатьТабличныйДокументИзExcel()
// Функция считывает в табличный документ данные из файла в формате Excel
//
// Параметры:
// ТабличныйДокумент — ТабличныйДокумент, в который необходимо прочитать данные
// ИмяФайла — имя файла в формате Excel, из которого необходимо прочитать данные
// НомерЛистаExcel — номер листа книги Excel, из которого необходимо прочитать данные
//
// Возвращаемое значение:
// Истина, если файл прочитан, Ложь — иначе
//
Функция мПрочитатьТабличныйДокументИзExcel(ТабличныйДокумент, ИмяФайла, НомерЛистаExcel = 1) Экспорт
xlLastCell = 11;
ВыбФайл = Новый Файл(ИмяФайла);
Если НЕ ВыбФайл.Существует() Тогда
Сообщить(«Файл не существует!»);
Возврат Ложь;
КонецЕсли;
Попытка
Excel = Новый COMОбъект(«Excel.Application»);
Excel.WorkBooks.Open(ИмяФайла);
Состояние(«Обработка файла Microsoft Excel…»);
ExcelЛист = Excel.Sheets(НомерЛистаExcel);
Исключение
Сообщить(«Ошибка. Возможно неверно указан номер листа книги Excel.»);
Возврат ложь;
КонецПопытки;
ТабличныйДокумент.Очистить();
ActiveCell = Excel.ActiveCell.SpecialCells(xlLastCell);
RowCount = ActiveCell.Row;
ColumnCount = ActiveCell.Column;
//+++ через буфер обмена
попытка
Excel.ActiveCell.SpecialCells(xlLastCell).Select();
Excel.Range( Excel.Selection, Excel.Cells(1)).Select();
Wsh = новый COMобъект(«Wscript.Shell»);
Excel.Selection.Copy();
Wsh.sendkeys(«#k8SjZc9Dxkc»);
Предупреждение(«Нажмите кнопку [Да] в следующем окна.
|Требуется сохранить данные в «»Буфер обмена»»
|для быстрой вставки сразу всех данных в 1С…»,30);
Excel.WorkBooks.Close();
Excel = 0;
//// Возврат Объект.ParentWindow.ClipboardData.Getdata(«Text»);
//// Снимим защиту и разрешим вывод
ТабличныйДокумент.Защита = Ложь;
ТабличныйДокумент.Вывод = ИспользованиеВывода.Разрешить;
ТабличныйДокумент.ТекущаяОбласть = ТабличныйДокумент.Область(1, 1, RowCount, ColumnCount);
рез = истина;
исключение
Предупреждение(ОписаниеОшибки());
рез = ложь;
КонецПопытки;
Предупреждение(«Нажмите [Ок] для «»мгновенной»» вставки «+строка(RowCount)+» строк из файла…»);
Wsh.sendkeys(«#k8SjZc9Dxkv»);
возврат рез;
//+++)
КонецФункции
(1) wildhog, благодарю!
Очень помогло.
вот эти 3 строчки искал в другом месте. Было бы здорово их включить в статью
(118) В статье основной посыл это метод работы с данными через comsafearray. А каким образом получен объект WorkSheets — вторично. В моем примере вообще читается текущий лист последней активной книги Excel.
Поэтому, спасибо за предложение, но в данному случае, имхо, это лишнее. К тому же в (7) этот код уже есть 😉
можно еще короче — открыть файл, удалить пустые строкистолбы вначале, использовать код
Особенности:
Читает сразу из открытого файла
Автоматический поиск заполненых ячеек. Если в начале есть пустые строкистолбы, то Excel может не правильно определить используемый диапазон (много лишнего). Проверить можно на листе нажав ctrl+shift+space
Обойти можно выделив вначале первую ячейку данных
ну и в последних релизах ПолучитьCOMОбъект перестал работать из не открытого файла. Если нужно из закрытого то