HelpF.pro

Загрузить данные в 1с из текстового файла с разделителями

В этой статье я расскажу, как загружать данные в 1с 8 из простейших текстовых файлов с разделителями. Обычно они имеют расширение csv (Comma-Separated Values). Т. е. название подразумевает, что в каждой строке такого текстового файла значения разделены запятой. Но на самом деле, запятую, в качестве разделителя, использовать не надёжно. Поэтому применяют другие разделители, которые в обычном тексте встречаются редко. Это могут быть символы «^», «~»,«|» и другие. Итак, наша задача состоит в том, чтобы загрузить имеющуюся в csv файле информацию в базу данных 1с. Например, в файле будут содержаться товары интернет - магазина. В качестве образца, я взял выгрузку из магазина на скрипте virtuemart. Посмотрим, как выглядит файл.
Привожу две первых строки из него:
Код
~product_sku~^~category_path~^~product_name~^~product_desc~
~20~^~Книги/Электронные книги~^~Amazon Kindle 4 Touch~^~<p>Популярная электронная книга с ч/б экраном 6", электронной бумагой E-Ink Pearl, разрешением 600x800 пикс. с 16 - ю оттенками серого.</p>~


Посмотрим на файл.
Первая строка служебная. В ней описан формат нашего файла. Т. е. в какой ячейке, что находится. Однако, имейте в виду, что такой строки может и не быть.
Ячейки образуются при помощи разделителя «^», а данные в ячейках обрамляются символом «~».
В любой конфигурации 1с есть иерархический справочник товаров. В него и будем загружать информацию.
Создадим внешнюю обработку. Добавим строковый реквизит «путьКФайлуЗагрузки» для хранения имени файла. Добавим на форму поле ввода, связанное с данным реквизитом. Включим в свойствах поля ввода кнопку выбора и создадим обработчик события «НачалоВыбора» и напишем в нём такой код:
Код 1C v 8.х
 Процедура путьКФайлуЗагрузкиНачалоВыбора(Элемент, СтандартнаяОбработка)
Режим = РежимДиалогаВыбораФайла.Открытие;
ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим);
ДиалогОткрытияФайла.ПолноеИмяФайла = "";
Фильтр = "Comma separated file (*.csv)|*.csv";
ДиалогОткрытияФайла.Фильтр = Фильтр;
ДиалогОткрытияФайла.МножественныйВыбор = Ложь;
ДиалогОткрытияФайла.Заголовок = "Выберите файл";

Если ДиалогОткрытияФайла.Выбрать() Тогда
путьКФайлуЗагрузки = ДиалогОткрытияФайла.ПолноеИмяФайла;
КонецЕсли;
КонецПроцедуры

Т. о. мы организовали диалог для выбора файла в нашей обработке.
Хорошо. Теперь, для удобства и наглядности я предлагаю создать временную табличку, в которую мы загрузим текстовый файл, а уже после её заполнения - будем осуществлять загрузку в базу 1с. Для этого, на форму добавим табличное поле «табЗагрузки», с типом значения «ТаблицаЗначений» и командной панелью. В панели поместим кнопку «Заполнить» и создадим обработчик её нажатия «КоманднаяПанель1Заполнить». Также для элемента универсальности, добавим в обработку два строковых реквизита «символОграничения» и «разделительПолей». В них мы будем хранить «^», и «~». Можно в теле модуля формы осуществить их начальную инициализацию:
разделительПолей = "^";
символОграничения = "~";
Это позволит пользователю задать свои значения и при желании сохранить настройку, которая впоследствии не затрется нашей инициализацией.
Код 1C v 8.х
 Процедура КоманднаяПанель1Заполнить(Кнопка)
Если табЗагрузки.Количество() > 0 И Вопрос("Таблица будет очищена. Вы уверены?",РежимДиалогаВопрос.ДаНет)
= КодВозвратаДиалога.Нет Тогда
Возврат;
КонецЕсли;
ЗаполнитьТаблицу();
КонецПроцедуры
Процедура ЗаполнитьТаблицу()
текст = Новый ТекстовыйДокумент;
Попытка
//обязательно устанавливаем кодировку, в которой наш файл
текст.Прочитать(путьКФайлуЗагрузки,КодировкаТекста.UTF8);
Исключение
Сообщить("Не удалось прочитать файл: "
+ ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат;
КонецПопытки;
табЗагрузки.Очистить();//очищаем таблицу
табЗагрузки.Колонки.Очистить();//удаляем колонки, так как их состав мог измениться
квоСтрок = текст.КоличествоСтрок();
Если Не квоСтрок > 0 Тогда
Сообщить("Файл пустой",СтатусСообщения.Внимание);
Возврат;
КонецЕсли;
//получаем первую строку с форматом файла
стрТекста = текст.ПолучитьСтроку(1);
//преобразуем строку в массив при помощи функции общего модуля, которая есть в типовых
//ниже я дам её код, на случай, если нет
масЗначСтр = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(стрТекста,разделительПолей);
//добавляем две служебные колонки
//для возможности отказаться от загрузки определенной строки
табЗагрузки.Колонки.Добавить("не_загружать",Новый ОписаниеТипов("Булево"),"Не загружать");
//для удобства вывода комментариев с указанием номера строки по ходу загрузки
табЗагрузки.Колонки.Добавить("номер_строки",Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(10,0,ДопустимыйЗнак.Неотрицательный)),"Номер строки");
//формируем колонки нашей таблицы
Для каждого зн Из масЗначСтр Цикл
//убираем лишний символОграничения
значение = СтрЗаменить(зн,символОграничения,"");
кол = табЗагрузки.Колонки.Добавить(значение,Новый ОписаниеТипов("Строка"));
КонецЦикла;

//создаём колонки в табличном поле
ЭлементыФормы.табЗагрузки.СоздатьКолонки();

//начиная со второй строки читаем строки файла, раскладывая их в массив
Для номСтр = 2 По квоСтрок Цикл
стрТекста = текст.ПолучитьСтроку(номСтр);
масЗначСтр = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(стрТекста,разделительПолей);
//добавляем новую строку в таблицу
новСтр = табЗагрузки.Добавить();
новСтр.номер_строки = номСтр;
//начиная с третьей колонки производим установку значений в колонки
номЗнач = 2;
Для каждого зн Из масЗначСтр Цикл
новСтр[номЗнач] = СтрЗаменить(зн,символОграничения,"");
номЗнач = номЗнач + 1;
КонецЦикла;
КонецЦикла;
КонецПроцедуры

Функцию разложения строки с разделителями в массив можно разместить как в одном из общих модулей, так и непосредственно в обработке.
Код 1C v 8.х
 Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",") Экспорт
МассивСтрок = Новый Массив();
Если Разделитель = " " Тогда
Стр = СокрЛП(Стр);
Пока Истина Цикл
Поз = Найти(Стр,Разделитель);
Если Поз=0 Тогда
МассивСтрок.Добавить(Стр);
Возврат МассивСтрок;
КонецЕсли;
МассивСтрок.Добавить(Лев(Стр,Поз-1));
Стр = СокрЛ(Сред(Стр,Поз));
КонецЦикла;
Иначе
ДлинаРазделителя = СтрДлина(Разделитель);
Пока Истина Цикл
Поз = Найти(Стр,Разделитель);
Если Поз=0 Тогда
МассивСтрок.Добавить(Стр);
Возврат МассивСтрок;
КонецЕсли;
МассивСтрок.Добавить(Лев(Стр,Поз-1));
Стр = Сред(Стр,Поз+ДлинаРазделителя);
КонецЦикла;
КонецЕсли;
КонецФункции

Отлично. В итоге, после заполнения, получим примерно такую картинку:
title

Теперь приступим непосредственно к загрузке товаров. Рядом с кнопкой «заполнить» добавим кнопку «загрузить» и добавим обработчик её нажатия «КоманднаяПанель1Загрузить», а также добавим реквизит «ПапкаЗагрузкиВыгрузкиТоваров» с типом вашего справочника товаров для опциональной их загрузки в определенную папку. Текст обработчика будет такой:
Код 1C v 8.х
 Процедура КоманднаяПанель1Загрузить(Кнопка)
Если Вопрос("Вы уверены, что хотите загрузить файл?", РежимДиалогаВопрос.ДаНет)
= КодВозвратаДиалога.Нет Тогда
Возврат;
КонецЕсли;
ВсегоСтрок = табЗагрузки.Количество();
номСтр = 1;
Для каждого стрТЗ Из табЗагрузки Цикл
Состояние("Обработано: " + Окр(номСтр * 100 / ВсегоСтрок) + "%");
номСтр = номСтр + 1;
ОбработкаПрерыванияПользователя();
//если пользователь установил не_загружать = Истина, пропускаем
Если стрТЗ.не_загружать Тогда
Продолжить;
КонецЕсли;
объект1С = вернутьТовар(стрТЗ);
Если объект1С = Неопределено Тогда
Возврат;
КонецЕсли;
Если Не ЗаписатьЭлементСпр(объект1С) Тогда
Сообщить("Загрузка прервана!",СтатусСообщения.ОченьВажное);
Возврат;
КонецЕсли;
//помечаем запись, как загруженную
стрТЗ.не_загружать = Истина;
КонецЦикла;
КонецПроцедуры

В приведенном коде две новые функции «вернутьТовар» и «ЗаписатьЭлементСпр». Вот их текст:
Код 1C v 8.х
 Функция вернутьТовар(стрТабФайла)
Артикул = стрТабФайла.product_sku;
Если Не ЗначениеЗаполнено(Артикул) Тогда
Сообщить("В строке " + стрТабФайла.номер_строки + " не заполнен product_sku",
СтатусСообщения.ОченьВажное);
Возврат Неопределено;
КонецЕсли;
Запрос = Новый Запрос("ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул = &Артикул");

Запрос.УстановитьПараметр("Артикул",Артикул);

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка.ПолучитьОбъект();
Иначе
ЭтоНовый = Истина;
объект1С = Справочники.Номенклатура.СоздатьЭлемент();
объект1С.Артикул = Артикул;
объект1С.Наименование = стрТабФайла.product_name;
объект1С.Родитель = вернутьРодителяТовара(стрТабФайла.category_path);
Возврат объект1С;
КонецЕсли;
КонецФункции // вернутьТовар()
Функция ЗаписатьЭлементСпр(Спр)
Попытка
Спр.Записать();
Исключение
Сообщить("При записи элемента справочника " + Спр + " возникла ошибка: " + ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат Ложь;
КонецПопытки;
Возврат Истина;
КонецФункции // ЗаписатьЭлементСпр()

И осталась последняя новая функция для обработки родителя товара вернутьРодителяТовара. Текст её смотрите ниже. Комментарии по тексту.
Код 1C v 8.х
 Функция вернутьРодителяТовара(стрКатегории)
//главный родитель - заполненная в обработке папка
Родитель = ПапкаЗагрузкиВыгрузкиТоваров;
//строку категории раскладываем в массив используя разделитель /
масРодителей = РазложитьСтрокуВМассивПодстрок(стрКатегории,"/");
Для каждого Род Из масРодителей Цикл
//если папку не находим, создаём и назначаем в качестве родителя
//следующей и т. д. В случае проблем выдаём прекращаем загрузку
РодСс = Справочники.Номенклатура.НайтиПоНаименованию(Род,Истина);
Если РодСс.Пустая() Тогда
НовРод = Справочники.Номенклатура.СоздатьГруппу();
НовРод.Наименование = Род;
НовРод.Родитель = Родитель;
Если Не ЗаписатьЭлементСпр(НовРод) Тогда
Возврат Неопределено;
КонецЕсли;
Родитель = НовРод.Ссылка;
Иначе
Родитель = РодСс;
КонецЕсли;
КонецЦикла;
Возврат Родитель;
КонецФункции //

Все. Конечно, в реальной жизни еще много чего нужно будет дописать, но не все сразу. Такой шаблон можно использовать как отправную точку. Скачивать файлы может только зарегистрированный пользователь!
Успехов в разработке!
Источник
Опубликовано на сайте: https://HelpF.pro
Прямая ссылка: https://HelpF.pro/faq82/view/1471.html