Выгрузка таблицы значений в Excel

Примитивно, грубо, без дизайна, но очень быстро.

Честно говоря, это не столько публикация, сколько антисклерозник для меня самого. Вот как Трактор делает — собрал свои наработки, укомпоновал и выложил, удобно отовсюду доставать. А поскольку я этот блок свой уже пару раз про…любил и заново написал, то во избежание — пусть будет таким образом. Как говорится, «в копипасте — щастье».

 

// Внимание! Исходная таблица тДанных должна содержать только данные простых типов!!!
Процедура БыстроВывестиТаблицуЗначенийВExcel(тДанных,рПутьИмяФайла,рОткрыватьДляПросмотра=Ложь) Экспорт
Попытка
    Если
тДанных.Количество()=0 Или ПустаяСтрока(рПутьИмяФайла) Тогда Возврат КонецЕсли;

    // если таблица для экселя спецслужебная, то выводим в двумерный массив, и теперь уже знаем его размеры
   
квоКолонокДЭ=тДанных.Колонки.Количество();
   
квоСтрокДЭ=тДанных.Количество()+1; // припуск на заголовок
   
РезДокумент=Новый Массив(квоКолонокДЭ,квоСтрокДЭ);

    // заголовки
   
мКолонокДат=Новый Массив;
    Для
итерКолонок=1 По квоКолонокДЭ Цикл
       
кол=тДанных.Колонки[итерКолонок1];
       
РезДокумент[итерКолонок1][0]=кол.Заголовок;
        Если
кол.ТипЗначения.СодержитТип(Тип(«Дата»)) Тогда мКолонокДат.Добавить(кол.Имя) КонецЕсли;
    КонецЦикла;

    // основные данные
   
квоиз=» из «+СокрЛП(квоСтрокДЭ1);
    Для
й=0 По квоСтрокДЭ2 Цикл
       
#Если Клиент Тогда
           
ОбработкаПрерыванияПользователя();
           
Состояние(«Вывод в Excel: «+Строка(й+1)+квоиз);
       
#КонецЕсли
       
стро=тДанных.Получить(й);
        Для
итерКолонок=1 По квоКолонокДЭ Цикл
           
знч=стро[итерКолонок1];
            Если
мКолонокДат.Найти(тДанных.Колонки[итерКолонок1])<>Неопределено Тогда
               
// выгрузка в эксель через COMSafeArray не понимает совсем пустые даты, поэтому надо это учесть!!!
               
знч=?(ЗначениеЗаполнено(знч),знч,Дата(1900,1,1));
            КонецЕсли;
           
РезДокумент[итерКолонок1][й+1]=знч;
        КонецЦикла;
    КонецЦикла;

    // сохраняем все в произвольный тип, подробнее см. типизацию в описании конструктора «По типу элемента 1»
   
рТипМассива=«VT_VARIANT»;
   
рМассив=Новый COMSafeArray(РезДокумент,рТипМассива,квоКолонокДЭ,квоСтрокДЭ);
   
Ексель=Новый COMОбъект(«Excel.Application»);
   
Книга=Ексель.Workbooks.Add();
    Если
Книга.WorkSheets.Count=0 Тогда
       
Лист=Книга.WorkSheets.Add();
    Иначе
       
Лист=Книга.WorkSheets.Item(1); // нумерация с 1
   
КонецЕсли;
   
// самое главное: диапазону ячеек можно просто присвоить SafeArray со значениями
   
рНачало=Лист.Cells(1,1);
   
рКонец=Лист.Cells(квоСтрокДЭ,квоКолонокДЭ);
   
Лист.Range(рНачало,рКонец).Value=рМассив;
   
//
    // соответствие форматов: xlOpenXMLWorkbook=51 это xlsx, xlExcel12=50 это xlsb, xlExcel8=56 это xls
   
стрпф=Новый Структура(«xls,xslx,xlsb»,56,51,50);
   
рФайл=Новый Файл(СокрЛП(рПутьИмяФайла));
   
расш=СтрЗаменить(рФайл.Расширение,«.»,«»);
   
рФормат=?(стрпф.Свойство(расш),стрпф[расш],51); // по умолчанию xlsx
   
Книга.SaveAs(СокрЛП(рПутьИмяФайла),рФормат);

    Если рОткрыватьДляПросмотра Тогда
       
#Если Клиент Тогда
           
Ексель.Visible=Истина;
       
#КонецЕсли
   
КонецЕсли;
   
//
   
Ексель=Null;

Исключение
    Сообщить(«БыстроВывестиТаблицуЗначенийВExcel, ошибка: «+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецПроцедуры

 

Желающим плюсить — сюда: //infostart.ru/public/269846/

Ну а первоисточник, который применял я, здесь: http://kb.mista.ru/article.php?id=707

Поскольку моё тут только конкретное воплощение, публикацию особо плюсить не стоит, и вообще она life.

28 Comments

  1. BigClock
    ТабЗнч = РезЗапроса.Выгрузить();
    ПострПечать = Новый ПостроительОтчета;
    ПострПечать.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабЗнч);
    ТабДок = Новый ТабличныйДокумент;
    ПострПечать.Вывести(ТабДок);
    ТабДок.Записать(«ИмяФайла.xls»);
    Reply
  2. vasyak319

    Всего вторую публикацию за сегодня читаю и уже второй способ удаления гланд через задницу. Сегодня «День проктолога» что ли?

    Reply
  3. DoctorRoza

    Вопрос в автору, как у гуру: можно в предложенном коде сделать «Попытку ..» не в блоке загрузки данных? То бишь, я хочу в начале проверить, что все загрузиться, а уже потом точно загружать данные! Спасибо!

    Reply
  4. Yashazz

    (1) BigClock, господин «пионэр», вы, вероятно, не поняли фишку, что, возможно, ввиду малого опыта простительно. Я ведь написал — это вариант быстрого способа. Да ещё и не подвешивающего клиентскую машину. Флаг вам в руки сохранять моксель на 300 тысяч строк методом Записать() при небольшой оперативке, тогда поймёте.

    (3) Что будет являться критерием «успешной загрузки» при проверке, и чем тогда, на ваш взгляд, загрузка будет отличаться от проверки оной?

    Reply
  5. Xershi

    (5) так работает типовой механизм. Куда не поставь 1С везде создаст файл эксель. Ваш вариант предполагает установку экселя на сервер с 1С. Что может быть и вообще не быстро, т.к. просто не создастся наш файл.

    Reply
  6. the1

    (5) вполне все работает. (не про производительность речь)

    Reply
  7. Yashazz

    (6), (7), мы с вами на разных 1С работаем, видимо, или у вас эксели ооочень сильно продвинутые. Позволю себе процитировать СП:

    ТабличныйДокумент (SpreadsheetDocument)

    Записать (Write)

    Синтаксис:

    Записать(<ИмяФайла>, <ТипФайлаТаблицы>)

    Параметры:

    <ИмяФайла> (обязательный)

    Тип: Строка.

    Имя файла, в котором сохраняется табличный документ.

    <ТипФайлаТаблицы> (необязательный)

    Тип: ТипФайлаТабличногоДокумента.

    Формат, в котором будет сохранен табличный документ.

    Значение по умолчанию: MXL.

    А теперь скажите мне, в приведённом фрагменте кода явно указан второй параметр, определяющий формат документа? Нет, не указан. А это означает, что эксель нихрена не откроет файл, сделанный таким образом. Желающие приглашаются проверить.

    Вообще это напоминает старый анекдот, как преобразовать pdf в вордовский файл — взять да и поменять расширение файла)))

    Reply
  8. vasyak319

    (8) а вот хамить не надо. Я понимаю, обидно, когда сидишь тут, ваяешь супермегастатью про свой убергиперспособ, а тут первый же комментатор пишет шесть строк кода, которые делают то же самое. И — о, чудо! о, подарок судьбы! — допускает мелкую ошибку. В коде, набитом на коленке чисто ради примера.

    Движок сайта не даёт ставить минусы чаще, чем раз в пять минут, но я никуда не тороплюсь.

    Reply
  9. webester

    (8) в (1) Действительно ошибка, но сам способ я использую тоже, не могу сказать про 300тыщ, это реально много, но я регулярно сохраняю таким образом в экселевккий файлик результат СКД отчета размером в 80К строк и десяток колонок, на стареньком ноуте со старым процом и 2гигами памяти. Занимает секунд 10-20 гдето, не могу сказать точнее.

    Reply
  10. Xershi

    (8) то, что там не указано расширение. Это косяк поста 1, но метод рабочий и расширение явно зададим и получим результат без тонны кода.

    Естественно для вывода простого отчета это то что нужно, ваш метод как раз таки не для таких случаем.

    Так что вопрос в задаче, а не быстроте/простоте!

    Reply
  11. zikonza

    Очень странно читать некоторые комментарии, с производительностью кто нибудь сталкивался вообще? С нагрузкой? С требованиями оптимизировать код? Автору плюс. Практически так же записываю.

    Reply
  12. zikonza

    (3) DoctorRoza, Не проще тогда все делать в транзакции?

    Reply
  13. Yashazz

    (13) zikonza, туманно представляю, чем может помочь транзакция. 1С ведь не будет откатывать изменения в стороннем клиентском приложении при отказе транзакции.

    Reply
  14. zikonza

    (14) не сохраню его так же,как и при попытке. По сути смысл тотже

    Reply
  15. Yashazz

    (16) zikonza, а, это да. Это вариант.

    Reply
  16. BigClock

    Yashazz,

    Да, в (1) есть косяк.

    Но в статье не было приведено никаких цифр (хотя бы ориентировочных) по сравнению Вашего способа с очевидным.

    Становится непонятным: стоит ли городить огород с такой большой процедурой?

    В (10) были приведены цифры. Очевидно, что для большинства применений этого простейшего способа из 6 строк более, чем достаточно.

    Насчёт «набитом на коленке» — знаете, вот клиенту потом трудно объяснить, что ошибка-то ерундовая. Потому что деление ошибок на ерундовые и серьёзные это признак неграмотного подхода. Любая ошибка, не позволяющая решить задачу — это серьёзная ошибка. И допущенная в цитируемом коде именно такова, сорри.

    Речь идет о подходе к решению задачи, а не о том, что именно этот код я буду внедрять у клиента. Тем более, что перед внедрением я обязательно проведу тестирование решения, в результате которого эта ошибка будет обнаружена.

    Reply
  17. Yashazz

    (18) BigClock,

    Но в статье не было приведено никаких цифр (хотя бы ориентировочных) по сравнению Вашего способа с очевидным.

    Не ставил такой цели. Я русским по белому написал, что это за публикация и зачем, а некоторые с таким жаром накинулись, будто я ноу-хау анонсировал. Прямо жаль, что того автора, ссылку на публикацию которого я привёл, так не комментили, потому что вон он понты раскидывал — не мне чета)

    Становится непонятным: стоит ли городить огород с такой большой процедурой?

    В моих случаях, в решениях промышленного масштаба, ещё как стоит.

    В (10) были приведены цифры. Очевидно, что для большинства применений этого простейшего способа из 6 строк более, чем достаточно.

    Согласен. Более того, если условия задачи допускают простое решение, то именно городить сложный огород и есть ошибка. Можно сделать просто — нужно сделать просто.

    Reply
  18. genayo

    (4) А 300 тысяч строк в Екселе нужны чтобы что с ними делать?

    Reply
  19. anosin

    (20) genayo, Например загрузить в другую систему, которая умеет грузить только из файла эксела

    Reply
  20. anosin

    ячейки с датами как сохранятся в экселе в приведнном коде? к примеру результат выводя СКД?

    Reply
  21. Yashazz

    (21) Именно.

    (22) anosin, как даты сохраняются. Или это не ко мне вопрос?

    Reply
  22. MadDAD

    Как отлавливаете незакрывшиеся процессы экселя на сервере?

    Reply
  23. Yashazz

    (24) MadDAD, правду сказать — никак. Всё руки не доходят заняться этой частью задачи.

    Reply
  24. androgin

    (8) Эксель отлично открывает формат MXL !

    Reply
  25. Yashazz

    (26) androgin, это в вас говорит или малый опыт, или большой оптимизм. Далеко не все версии и далеко не всегда способны открыть mxl. А иногда вроде и открывают, но лучше бы отказались, таков бывает результат.

    Reply
  26. Ivon

    Не понимаю восторгов автора от собственного творения. Метод не самый быстрый, хотя и не самый медленный. Но самый главный минус — использование Excel для выгрузки просто таблицы значений без форматирования. Копайте в сторону ADO и будет вам счастье — там можно выгружать и в Excel и в Access не имея установленного офиса.

    Reply
  27. Yashazz

    (28) Ivon, во-первых, восторгов особых вроде не вижу. Покажите, где вы их нашли, а? Уж не фраза ли «публикацию особо плюсить не стоит» это восторг?

    Во-вторых, спасибо, но механикой ADO я владею в достаточной мере.

    В третьих, если кто-то справедливо раскритиковал вашу разработку, ползать по ИС и цепляться к его работам — ну, несколько странно выглядит.

    Reply
  28. Ivon

    (29) Если вы так хорошо во всем разбираетесь, зачем постить подобный шлак. И это тоже справедливая критика

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *