Как программно выгрузить любой документ 1С в текстовый файл и загрузить его обратно

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработка механизмов обмена данными — это одна из наиболее частых задач, с которыми сталкивается программист 1С. Иногда условия задачи (например, тестовое задание или специфические требования интеграции) ограничивают нас в использовании стандартных средств вроде XML или JSON. В таких случаях нам приходится создавать собственный текстовый формат экспорта и импорта. В этой статье мы подробно разберем, как реализовать универсальную выгрузку любого документа в обычный .txt файл и как затем создать на его основе копию документа в базе.

Почему нельзя просто записать ссылку в файл

Начинающие разработчики часто совершают ошибку, пытаясь записать объект документа напрямую в текстовый файл. Проанализируем ситуацию: если мы напишем ЗаписьТекста.ЗаписатьСтроку(ДокументСсылка), в файл попадет лишь строковое представление (например, "Реализация товаров №1 от 01.01.2023"). Этих данных недостаточно для воссоздания документа. Чтобы получить полную копию, нам нужно извлечь значения всех его реквизитов (Дата, Номер, Контрагент, Склад и т.д.) и всех строк его табличных частей.

Шаг 1: Работа с метаданными для универсальной выгрузки

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

Сначала нам нужно получить объект документа из ссылки. Выясним причину: только объект (тип ДокументОбъект) предоставляет полный доступ к данным для чтения и записи. Затем мы обратимся к коллекции метаданных этого объекта.


// Получаем объект из ссылки, выбранной на форме
ВыгружаемыйОбъект = РеквизитДокументСсылка.ПолучитьОбъект();
ИмяДокумента = ВыгружаемыйОбъект.Метаданные().Имя;

// Создаем объект для записи текста
Запись = Новый ЗаписьТекста("C:\Temp\ExportDoc.txt", КодировкаТекста.UTF8);

// 1. Записываем имя вида документа, чтобы знать, что создавать при загрузке
Запись.ЗаписатьСтроку("ВидДокумента:" + ИмяДокумента);

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

Шаг 2: Обработка ссылочных типов и сложных данных

Проанализируем важный нюанс: в 1С реквизиты могут быть простыми (Число, Строка, Дата) и ссылочными (СправочникСсылка, ДокументСсылка). Если мы просто запишем Строка(Значение) для справочника "Контрагенты", мы получим его наименование. Но при загрузке в другую базу (или даже в эту же) наименования могут дублироваться.

Рекомендация: Для обеспечения уникальности лучше выгружать УникальныйИдентификатор ссылки. Посмотрим на пример функции преобразования:


Функция ПреобразоватьЗначениеВТекст(Значение)
    ТипЗнч = ТипЗнч(Значение);
    
    Если ТипЗнч = Тип("Дата") Тогда
        // Используем универсальный формат даты ГГГГММДДЧЧММСС
        Возврат Формат(Значение, "ДФ=ггггММддЧЧммсс");
    ИначеЕсли Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч) Тогда
        // Для справочников пишем GUID и тип для поиска
        Возврат Строка(Значение.УникальныйИдентификатор()) + "|" + Значение.Метаданные().Имя;
    Иначе
        Возврат Строка(Значение);
    КонецЕсли;
КонецФункции

Шаг 3: Выгрузка табличных частей

Документ — это не только шапка, но и таблицы (например, "Товары"). Разберем по шагам, как их выгрузить. Нам нужно обойти все табличные части, а внутри каждой — все строки и все колонки.


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

Шаг 4: Загрузка данных и создание нового документа

Теперь рассмотрим обратный процесс. Чтобы загрузить документ, нам нужно прочитать текстовый файл построчно, определить вид документа и заполнить его реквизиты.

Проанализируем алгоритм загрузки:

  1. Создаем чтение файла через ЧтениеТекста.
  2. Первой строкой получаем вид документа и создаем новый объект: НовыйДокумент = Документы[ИмяВида].СоздатьДокумент();.
  3. В цикле читаем строки. Если строка содержит "имя=значение", заполняем шапку.
  4. Если встречаем маркер таблицы, переходим в режим заполнения строк табличной части.
  5. Важно: Для ссылочных типов нужно выполнить поиск в базе по GUID.

// Пример восстановления ссылки по GUID
Идентификатор = Новый УникальныйИдентификатор(СчитанныйGUID);
СсылкаНаОбъект = Справочники[ИмяСправочника].ПолучитьСсылку(Идентификатор);

После заполнения всех полей необходимо вызвать метод НовыйДокумент.Записать();. Обратите внимание, что номер документа лучше оставить пустым или очистить, чтобы система 1С автоматически присвоила новый уникальный номер при записи, как и требовалось в задаче.

Альтернативные и быстрые способы

Если задача не ограничивает вас строгим самописным форматом .txt, рассмотрим еще два профессиональных подхода:

1. Использование ЗначениеВСтрокуВнутр. Это "старый" способ 1С, который превращает любой объект в специальную системную строку. Рассмотрим пример:


// Выгрузка
ТекстОбъекта = ЗначениеВСтрокуВнутр(ВыгружаемыйОбъект);
// Загрузка
НовыйОбъект = ЗначениеИзСтрокиВнутр(ТекстОбъекта);
НовыйОбъект.УстановитьСсылкуНового(Документы.РеализацияТоваровУслуг.ПолучитьСсылку());
НовыйОбъект.Записать();

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

2. Сериализация в XML. Это стандарт индустрии. Как было предложено на форуме, вы можете использовать ЗаписатьXML(). Выясним, в чем преимущество: система сама обойдет все реквизиты и табличные части, сохранив структуру документа идеально.


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Doc.xml");
ЗаписатьXML(ЗаписьXML, ВыгружаемыйОбъект);
ЗаписьXML.Закрыть();

Подведем итоги

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

Для дальнейшего изучения темы рекомендуем обратиться к книге "Практическое пособие разработчика" (автор Радченко), где подробно описываются механизмы работы с объектами и метаданными платформы 1С:Предприятие.

← На главную