Я его слепила из того, что было. Два файла Excel в один.

Когда встает задача сделать что-нибудь с файлами Excel, лично я чувствую себя как человек с завязанными глазами, идущий по полю с граблями. Матерясь, наступаю на грабли, но все равно иду вперед. И вот в очередной раз встала задача, на которую в прошлые разы ответа на просторах интернета найдено не было. Склеить два листа EXCEL в один.

Ну что ж, приступим.

Казалось бы задача проста:

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

Решение:

1. Создаем экземпляр эксель, книгу, лист  (это понятно)

2. Если в нашем файле эксель есть картинки, как например у меня, вписанные в ячейки, то если не скопировать формат колонок в наш новый лист эксель, их покорежит. Поэтому копируем формат колонок из листа приемника в лист источник.

Процедура ФорматироватьШиринуКолонок(ЛистИсточник, ЛистПриемник)

КоординатыИсточник = КоординатыОбласти(ЛистИсточник);
ДиапазонИсточник = ДиапазонОбласти(ЛистИсточник,КоординатыИсточник);
КопироватьШиринуСтолбцовДиапазона(ЛистПриемник, КоординатыИсточник, ДиапазонИсточник);

КонецПроцедуры

Функция КоординатыОбласти(Лист)

НачальнаяКолонка = 1;
НачальнаяСтрока    = 1;
КонечнаяКолонка    = Лист.Cells.CurrentRegion.Columns.Count;
КонечнаяСтрока = Лист.UsedRange.Rows.Count;

СтруктураКоординат = Новый Структура("НачальнаяКолонка,НачальнаяСтрока,КонечнаяКолонка,КонечнаяСтрока",
НачальнаяКолонка,НачальнаяСтрока,КонечнаяКолонка,КонечнаяСтрока);
Возврат СтруктураКоординат;

КонецФункции

Функция ДиапазонОбласти(Лист, Координаты)

Диапазон = Лист.Range(Лист.Cells(Координаты.НачальнаяСтрока, Координаты.НачальнаяКолонка),
Лист.Cells(Координаты.КонечнаяСтрока, Координаты.КонечнаяКолонка));
Возврат Диапазон;

КонецФункции // ()

Процедура КопироватьШиринуСтолбцовДиапазона(ЛистПриемник, Координаты, Диапазон)

Диапазон.Copy(); //записали в буфер
ЛистПриемник.Range(ЛистПриемник.Cells(Координаты.НачальнаяСтрока, Координаты.НачальнаяКолонка),
ЛистПриемник.Cells(Координаты.НачальнаяСтрока+Координаты.КонечнаяСтрока-1,
// цифра 8 означает сохранить ширину столбцов как в источнике.
Координаты.НачальнаяКолонка+Координаты.КонечнаяКолонка-1)).PasteSpecial(8);

КонецПроцедуры

3. Осталось дело за малым — скопировать лист.

Для этого мы обязательно должны:

— Активировать лист источник

Процедура АктивироватьЛист(Лист)

Лист.Activate();

КонецПроцедуры

— Выделить диапазон копирования

Процедура ВыделитьДиапазон(Лист, НачальнаяСтрока, КонечнаяСтрока)

ДиапазонСтрок = Лист.Rows("" + Строка(НачальнаяСтрока) + ":" + Строка(КонечнаяСтрока));
ДиапазонСтрок.Select();

КонецПроцедуры

— Копировать выделение в буфер

Процедура КопироватьВыделениеВБуфер(Эксель)

Эксель.Selection.Copy();

КонецПроцедуры

— Активировать лист приемник

— Выделить диапазон вставки

— И собственно вставить

Процедура ВставитьВыделенное(Эксель)

Эксель.Selection.Insert(-4121);

КонецПроцедуры

— не забудем выделение снять

Процедура СнятьВыделение(Эксель)

Эксель.Selection.Cells(1).Select();

КонецПроцедуры

Вся процедура выглядит так

Процедура СкопироватьЛистЭксельВКонец(Эксель, ЛистИсточник, ЛистПриемник, КоличествоСтрокОтступа, ЛистФормата = Ложь)

//Получим координаты областей
КоординатыИсточника = КоординатыОбласти(ЛистИсточник);
КоординатыПриемника = КоординатыОбласти(ЛистПриемник);

//Для выделения диапазона строк сначала обязательно надо активировать лист в котором производится выделение
АктивироватьЛист(ЛистИсточник);
ВыделитьДиапазон(ЛистИсточник, КоординатыИсточника.НачальнаяСтрока, КоординатыИсточника.КонечнаяСтрока);
КопироватьВыделениеВБуфер(Эксель);

АктивироватьЛист(ЛистПриемник);

//При создании новой книги в ней присутствуют 3 пустых строки
//Что бы была только одна для первого копируемого листа установим начальную строку
Если ЛистФормата Тогда
НомерСтрокиНачалаВставки = 1;
Иначе
НомерСтрокиНачалаВставки = КоординатыПриемника.КонечнаяСтрока + КоличествоСтрокОтступа + 1;
КонецЕсли;

НомерСтрокиКонцаВставки  = НомерСтрокиНачалаВставки + КоординатыИсточника.КонечнаяСтрока;
ВыделитьДиапазон(ЛистПриемник, НомерСтрокиНачалаВставки, НомерСтрокиКонцаВставки);

ВставитьВыделенное(Эксель);

СнятьВыделение(Эксель);

КонецПроцедуры

Вот собственно и все. Как говорится: «Ловкость рук и никакого мошейничества».

Прикладываю обработку слияния файлов, которую при необходимости вы легко сможете применять в любой своей конфигурации. Все что ей нужно — дать на вход массив путей ваших однотипных файлов эксель, а на выходе получить их квинтэссенцию. Либо просто заполнить табличную часть путями к файлам

36 Comments

  1. alsoftik

    Это конечно прикольно, на 1С склеивать 2 excel файла,

    но в чем профит?

    Reply
  2. dka80

    А зачем что-то делать в Эксель, если есть 1С?

    Reply
  3. DoctorRoza

    В чисто исследовательских целях, очень даже интересно, хотя .. на кой это нужно!? 🙂

    Reply
  4. Den_D

    (1) alsoftik, (2) dka80, (3) DoctorRoza, в моем случае есть линия постовой сборки, технологи пишут инструкцию на каждый пост. На каждый пост своя инструкция и соответственно свой файл эксель. Что бы составить инструкцию на всю линию по каждому изделию я применил этот механизм. Зачем в прошлый раз вставала эта задача я уже не могу припомнить, но факт в том, что это надо было сделать так как оно реализовано.

    Reply
  5. AnryMc

    Мы не ищем легких путей!


    Sheets(«Лист2»).Select

    Sheets(«Лист2»).Copy Before:=Sheets(1)
    Reply
  6. AnryMc

    Точнее так


    Workbooks.Add

    Windows(«Книга1»).Activate

    Sheets(«Лист1»).Select

    Sheets(«Лист1»).Move After:=Workbooks(«Книга2»).Sheets(3)
    Reply
  7. AnryMc

    (5) AnryMc, (6) AnryMc,

    Пардон, невнимательно посмотрел, что всё надо «влепить» на один лист книги….

    Reply
  8. Hellgga

    Добрый день.

    Обратитесь на форум «Планета Эксель» и Вам там обязательно помогут. 🙂

    Reply
  9. Den_D

    (8) Hellgga, не думаю, что там кто-то напишет за меня на языке 1С 🙂

    Reply
  10. Hellgga

    Ясное дело, что на языке 1С не напишут (хотя, как знать ;)) — форум-то экселевский.

    А вот макрос для документа, сохранённого в экселе, очень даже напишут 🙂

    Reply
  11. Den_D

    (10) Hellgga, макрос можно и самому сделать))) потом посмотреть что он там понаписал) этим методом тоже пользуюсь периодически, но макрос не всегда делает оптимально конечно при этом.

    Reply
  12. Hellgga

    Посмотреть, что он там понаписал! Это макрорекордером, что ли?

    Макрорекордером это как след не напишешь…

    Reply
  13. Klyacksa

    Зачем копировать формат колонок? Почему нельзя было взять за основу один из файлов, сохранить его копию и добавлять сразу в него? Если уж формат у всех одинаковый…

    Reply
  14. Den_D

    (12) Hellgga, не владею термином «макрорекордер». Просто включаешь запись макроса, делаешь, то что надо руками. Останавливаешь запись макроса и смотришь как это все выглядит на Visual Basic

    Reply
  15. Den_D

    (13) Klyacksa, можно сделать и так, но тут могут возникнуть тонкости. Как например, если вдруг пользователь хочет слепить файлы, посмотреть на результат и сохранить результат в отдельный файл. В вашем варианте существует возможность, что пользователь просто нажмет записать и таким образом перезапишет исходный файл. Хотя если копию… можно и копию…

    Reply
  16. Hellgga

    (14) так это и есть «запись макроса макрорекордером»; что-нибудь простенькое им можно наваять, а в Вашем случае надобно писать полноценный макрос.:)

    Reply
  17. DrAku1a

    (16), Дааа… Это просто офигительный сложный макрос:

    AnryMc написал в (6):


    Workbooks.Add

    Windows(«Книга1»).Activate

    Sheets(«Лист1»).Select

    Sheets(«Лист1»).Move After:=Workbooks(«Книга2»).Sheets(3)
    Reply
  18. webester

    Как и остальные, не совсем понял, что делал автор. После прочтения статьи появились вопросы:

    1. Автор изучает возможности доступные для экселя из vba методом тыка? Так вроде же документация существует.

    2. Не понял, почему технологи не могут колотить сразу в 1Стекстовый документкуда угодно. Что бы сразу с нуля формировать нужный эксель из 1С, легкими движениями и без граблей. То есть в целом я бы начал со сбора и обработки данных. Если это возможно конечно.

    3. Если просто есть 2 экселя и нужно сделать один, причем здесь 1С?

    4. Почему работа с эксель у автора похожа на хождение по граблям? Ведь есть же документация?

    Reply
  19. viramen

    В офисе есть отличный механизм — запись макроса. Включаешь, выполняешь необходимые действия — смотришь получившийся код. Пользы от статьи — 0.

    Reply
  20. Den_D

    (18) webester, мне поставлена задача, я ее решаю исходя из тех условий которые есть. По второму пункту, инструкции в файлах должны быть доступны в не зависимости от работоспособности 1С. По третьему пункту, если файлов эксель 2, то действительно проблем никаких и 1С не надо, но если постов 20 шт. на каждый пост по инструкции, при этом могут менятся как инструкции так и количество постов, то задача составить полную инструкцию на линию перестает быть такой тривиальной. По пункту №4: Если у вас есть документация по эксель полнее чем MDSN, буду рад, если вы со мной поделитесь.

    Reply
  21. gaglo

    (20) Вот чессно слово, если бы автор сразу написал, что постов 15-25, а инструкции меняются в среднем еженедельно, то вопросов «на фиг это надо» было бы меньше. кроме одного…

    Зачем было делать это на VBA через 1С, а не в родной среде VBA? Неужто «так легче»?

    Reply
  22. Den_D

    (21) gaglo, ответ очень прост, я не владею VBA, но владею 1С. Поэтому я не понимаю, что вы имеете в виду говоря, что это можно было сделать в среде VBA, если вы мне дадите более развернутый ответ, как это можно сделать я буду признателен и обязательно изучу эту возможность для саморазвития.

    Reply
  23. Hellgga

    Извините, ради Бога,за то, что вмешиваюсь в Ващ диалог…

    Если Вы владеете 1С, то, не грех бы, владеть и VBA, поскольку 1С и Эксель всё-таки, хоть немного, но связаны.

    А на VBA можно решать оочень многие вопросы (выгруженные из 1С)

    Ещё раз, извините.

    С уважением,

    Ольга

    Reply
  24. Den_D

    (23) Hellgga, конечно не грех. Но согласитесь, в 1с множество вопросов, которые следует изучать и как это обычно бывает мы изучаем то, что нам нужно для решения текущих задач, придумывать себе мифические задачи и изучать их решение достаточно трудоемкая задача при большой текущей нагрузке.

    Свободного времени всегда не хватает. Шутка: Раз уж мы владеем 1С не грех и научится плавать на собственной яхте ))

    Reply
  25. Hellgga

    🙂

    Эт точно. Для тех, кто владеет 🙂

    Reply
  26. gaglo

    (22) и (24) — Похвастун! Это 1С владеет вами! (Если свободного времени не хватает «всегда» — задумайтесь!)

    Если серьезно, то «можно было сделать в среде VBA» значит именно то, что написано.

    Открыть Excel, в нем редактор VBA, написать процедуры, вытащить на лист рабочей книги кнопку и посадить на нее вызов этой процедуры…

    Только вместо

    Процедура СкопироватьЛистЭксельВКонец(Эксель, ЛистИсточник, ЛистПриемник, КоличествоСтрокОтступа, ЛистФормата = Ложь)

    было бы

    Sub CopyExcelSheetToEnd(SheetFrom, SheetTo, NumIndentRows, SheetFormat)…

    а вместо

    Эксель.Selection.Insert(-4121);

    что-то вроде

    ActiveSheet.Selection.Insert(xlShiftDown)

    (примерно, конечно)

    Reply
  27. Klyacksa

    Чего все так накинулись на то, что автор склеивала файлы через 1С, а не непосредственно из VBA? Нормальная задача, тем более что дальше напрашивается расширение задачи — если нужно «клеить» файлы постоянно, в 1С делаем регламентную задачу с расписанием — и забываем даже про «нажатие» кнопочки в обработке. Ну конечно, при условии клиент-серверного варианта базы и возможности хоть как-то составить расписание (например, раз в день, или раз в неделю).

    (15) я имела ввиду копию конечно, да… сами исходные файлы только на чтение, чтобы ни в коем случае их не повредить — хороший тон.

    Reply
  28. Aleksey81

    На самом деле интересен феномен, что такая простая разработка так оказалась востребована (25 плюсов спустя 4 дня). Можно сколько угодно ругать автора, но количество плюсов делает все эти нападки бессмысленными. Думаю польза от этой публикации в том что она дала легкий старт тем кто хотел написать более сложные алгоритмы на том же 1С механизме.

    Возможно авторы правы, что надо знать VBA, но тут сразу возникает вопрос:

    Если менее 5% твоей работы касается Экселевских документов — следует:

    а) Профессионально изучать VBA и использовать его

    б) Разобраться в азах VBA, сделать работу на VBA и потом долго исправлять косяки и обидные ошибки

    в) Реализовать все на той платформе, где ты себя чувствуешь рыбой в воде, то есть 1С.

    Вопрос не однозначный и можно бесконечно спорить по его решению. Но каждое решение имеет право на жизнь.

    Reply
  29. Den_D

    (26) gaglo, да, это здорово, но не в контексте решаемой задачи.

    Если еще чуть подробнее, то показ инструкции на посте происходит по прибытии продукции на пост каждые 7 минут, происходит сканирование серийного номера, в зависимости от модели продукции инструкция выдается работнику, это же событие фиксируется в системе, для последующего анализа времени нахождения продукции на отдельных постах, линиях, участках. Возможно автоматическое создание документов. Поэтому логичнее все действия выполнять при помощи одной системы, в данном случае на базе 1С. Никто не нажимает никаких кнопок в эксель, только сканирование.

    (28) Aleksey81, Спасибо, все верно, зачем тратить время на изучение не нужных вещей.

    (27) Klyacksa, в моей задаче получается что результирующий файл не нужен на диске, он нужен в момент сканирования устройства и формируется на основании модели. Вот почему лишняя запись файла на диск была просто не нужна.

    Reply
  30. Klyacksa

    (29) вот тут не поняла. Что имеется ввиду под «лишней записи файла на диск»?

    Ваше решение: берем пустой файл, копируем туда колонки из первого файла, и дальше дописываем из остальных файлов.

    Мое предложение: берем первый файл, копируем его целиком (при этом не обязательно его куда-то записывать!), и дальше дописываем из остальных файлов.

    Итого разница — «бегаем» по первому файлу, или копируем его системными средствами, вот и вся разница. Никакой доп.записи.

    Reply
  31. Den_D

    (30) Klyacksa,

    берем первый файл, копируем его целиком (при этом не обязательно его куда-то записывать!)

    а это как? если мы его копируем, разве это не значит, что мы его копию записываем на диск?

    Reply
  32. Klyacksa

    (31) да, действительно, создавать новый файл все-равно придется.

    Но копировать-то можно сразу весь лист первого файла целиком:

     Excel = Новый COMОбъект(«Excel.Application»);
    Книга = Excel.WorkBooks.Add();
    КнигаТемп = Excel.WorkBooks.Open(«D:	empaaa.xls»);
    
    ЛистШаблона = КнигаТемп.WorkSheets(1);
    ЛистШаблона.Copy(Книга.Sheets(1));
    
    Reply
  33. Den_D

    Если скопировать первый файлиз списка файлов, то первый лист можно не копировать, а сразу лепить к нему все оставшиеся. Потом надо за собой убрать и удалить эту копию. Тут я с вами согласен, такой вариант тоже возможен, а можно просто скопировать формат ))

    Reply
  34. gaglo

    (27) Накинулись, накинулись… Вот я объясню, почему я «накинулся». Если бы в публикации сразу было написано, что инструкцию надо собирать и показывать каждые 7 минут, да по-разному, в зависимости от текущего изделия — я бы и не вспоминал про «чистый VBA», потому что он тут действительно не к месту. А пока формулировки типа «мне поставили задачу, я ее решаю» — задачу-то не раскрывали полностью — пока все и удивлялись, почему это прямо в 1С надо делать…

    Reply
  35. gaglo

    (28) Дело в том, что 24 этих скачивания у меня лично вызывают подозрения, что сделаны на всякий случай людьми, которые читают только свежие публикации, а поиском по Инфостарту почему-то не пользуются. Потому как тут за прошлые годы ну очень много насчет взаимодействия с Excel накопилось…

    А ещё: «знать VBA» — если точнее, сам язык VBA достаточно прост, чтоб сказать, что там и знать-то нечего. А вот познать объектную модель документа Excel (вот эти вот Range, Cells, Activate) приходится независимо от того, на каком языке решаем мы нашу нелегкую задачу, уж если связались с файлами Excel вообще. Я лично понял, что именно познание этих методов и объектов сравнивал автор с «хождением по граблям».

    А VBA знать не надо, так и договоримся.

    Reply
  36. xrrg

    к вящей славе автора и к моей потере времени поисковик на тематический запрос выводит на эту статью. простое копирование кода не взлетело почему-то. мож потому что на сервере. не было смысла разбираться, тк можно чуток проще — так, как советуют «знатоки vba».

    содержимое TempSheet одной книги добавляется в SheetDest другой. сохранение формата достигается в моем случае макетами СКД и условным оформлением.

    xlCellTypeLastCell = 11;
    
    MaxRow = TempSheet.Cells.SpecialCells(xlCellTypeLastCell).Row;
    Diapason = TempSheet.Rows(«1:» + Формат(MaxRow, «ЧГ=0»));
    
    SheetDest = Book.ActiveSheet;
    MaxRowDest = SheetDest.Cells.SpecialCells(xlCellTypeLastCell).Row;
    DiapasonDest = SheetDest.Rows(Формат(MaxRowDest + 1, «ЧГ=0») + «:» + Формат(MaxRowDest + 1 + MaxRow, «ЧГ=0»));
    
    Diapason.Copy(DiapasonDest);

    Показать

    активизировать листы необязательно, можно просто присвоить sheetdest = book.sheets(1);

    Reply

Leave a Comment

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