В практике разработчика на платформе 1С:Предприятие 7.7 часто возникает задача импорта данных из внешних источников, таких как текстовые файлы (TXT или CSV). Одной из наиболее распространенных проблем является некорректная логика создания документов в цикле, когда вместо набора документов создается лишь один или данные записываются некорректно. В этой статье мы подробно разберем, как реализовать надежный алгоритм парсинга файла и создания документов, проанализируем типичные ошибки и рассмотрим способы оптимизации процесса.
Рассмотрим ситуацию: нам необходимо прочитать текстовый файл, в котором начало данных документа помечено разделителем ----------, а конец — разделителем __________. Между этими строками находятся данные для реквизитов (дата, номер, основание и т.д.).
Разберем основные ошибки, которые часто допускают начинающие разработчики в 1С 7.7:
Найти(). Например, если ТекСтр — это порядковый номер строки (число), то попытка найти в нем дефисы Найти(ТекСтр, "---") всегда будет возвращать 0.ДокМарк.Новый() не в том месте, программа может либо перезаписывать один и тот же объект, либо выдавать ошибку уникальности номера.Для и ручное увеличение счетчика внутри него часто приводят к пропуску строк или бесконечным циклам.Для корректной работы с объектом Текст в 1С 7.7 лучше всего использовать последовательный обход строк. Разберем наиболее эффективный подход к реализации этой задачи.
Проанализируем ситуацию: нам нужно инициализировать объект документа только тогда, когда мы встретили начало блока данных, и записывать его, когда блок завершен. Посмотрим на пример кода:
Перем Т;
Т = СоздатьОбъект("Текст");
Т.Открыть(ПутьКФайлу);
ДокМарк = СоздатьОбъект("Документ.Маркировка");
// Начинаем перебор строк файла
Для Ном = 1 По Т.КоличествоСтрок() Цикл
ТекСтр = Т.ПолучитьСтроку(Ном);
Стр = СокрЛП(ТекСтр);
// Проверяем начало блока документа
Если Лев(Стр, 5) = "-----" Тогда
ДокМарк.Новый();
ФлагЗаполнения = 1; // Маркер того, что мы внутри документа
Продолжить;
КонецЕсли;
// Если мы внутри блока данных — заполняем реквизиты
Если ФлагЗаполнения = 1 Тогда
// Здесь должна быть логика определения, какой реквизит в какой строке
// Для примера предположим, что данные идут в строгом порядке
// Но лучше использовать дополнительные условия или счетчик внутри блока
КонецЕсли;
// Проверяем конец блока документа
Если Найти(Стр, "__________") > 0 Тогда
Если ДокМарк.Выбран() = 0 Тогда // Проверка, что документ инициализирован
ДокМарк.Записать();
ФлагЗаполнения = 0;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Выясним причину, по которой создание большого количества документов может занимать много времени. В 1С 7.7 каждая команда Записать() инициирует обращение к диску и обновление индексных файлов базы данных. Если документов сотни или тысячи, процесс замедляется в геометрической прогрессии.
Для ускорения процесса мы рекомендуем использовать механизм транзакций. Обернув цикл создания в транзакцию, вы заставляете систему накопить изменения в оперативной памяти и записать их на диск одним блоком.
Рассмотрим, как изменить код:
НачатьТранзакцию();
Попытка
Для Ном = 1 По Т.КоличествоСтрок() Цикл
// ... код парсинга и записи документов ...
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Произошла ошибка при импорте: " + ОписаниеОшибки());
КонецПопытки;
Важно: При использовании транзакций в многопользовательском режиме помните о блокировках. Если импорт занимает слишком много времени, другие пользователи не смогут записывать документы этого же типа.
При чтении из текстового файла все данные изначально являются строковыми (String). Выясним, как правильно преобразовывать их в типы данных 1С.
Дата(Стр). Если дата в файле записана в нестандартном формате (например, "ДД.ММ.ГГГГ"), используйте функции Лев(), Сред() и Прав() для сборки правильной строки.Число(Стр), предварительно очистив строку от лишних пробелов с помощью СокрЛП().ДокМарк.УстановитьНовыйНомер(). Если номер берется из файла, убедитесь, что он уникален, иначе метод Записать() вернет 0.Если ваш документ Маркировка содержит табличную часть, логика внутри цикла усложняется. Проанализируем ситуацию, когда между разделителями находится неопределенное количество строк продукции.
В этом случае внутри основного цикла чтения файла мы должны использовать метод ДокМарк.НоваяСтрока() каждый раз, когда встречаем строку с данными товара. Рассмотрим пример структуры такого цикла:
// ... внутри блока, где документ уже создан через .Новый() ...
Если (Стр <> "-----") И (Стр <> "_____") Тогда
ДокМарк.НоваяСтрока();
ДокМарк.Товар = НайтиТоварПоНаименованию(Стр); // Пример функции поиска
ДокМарк.Количество = 1;
КонецЕсли;
Никогда не пренебрегайте проверкой результата метода Записать(). В 1С 7.7 этот метод возвращает 1 в случае успеха и 0 в случае неудачи (например, если не заполнено обязательное поле или сработала проверка в модуле документа).
Проанализируем пример с обработкой ошибок:
Если ДокМарк.Записать() = 0 Тогда
Сообщить("Не удалось записать документ в строке файла: " + Ном, "!");
КонецЕсли;
Это позволит пользователю быстро найти проблемное место в исходном текстовом файле и исправить данные без необходимости повторного импорта всего массива строк.
Резюмируя вышесказанное, при создании документов в цикле из текстового файла в 1С 7.7 придерживайтесь следующих правил:
СокрЛП() для очистки строк от невидимых символов.СоздатьОбъект вызывался один раз перед циклом, а Новый() — строго при обнаружении разделителя начала документа.Лев(Стр, N) для сравнения разделителей, чтобы избежать проблем с лишними пробелами или дефисами в конце строки.НачатьТранзакцию() и ЗафиксироватьТранзакцию().Т.ПолучитьСтроку(Ном) эффективнее будет работать последовательное чтение с использованием Т.ВыбратьСтроки() и Т.ПолучитьСтроку().Соблюдение этих простых правил сделает ваш код надежным, быстрым и удобным для поддержки другими разработчиками.