Выгрузка таблицы значений в 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 не будет опубликован. Обязательные поля помечены *