В процессе автоматизации часто возникает задача импорта данных из внешних текстовых файлов. Например, когда нужно прочитать список строк определенного формата, найти по части этой строки соответствующий документ в базе 1С и заполнить его реквизиты оставшейся информацией. Рассмотрим подробно, как реализовать этот алгоритм максимально эффективно и отказоустойчиво.
Для начала нам необходимо получить список файлов в целевом каталоге и прочитать их содержимое. В 1С для поиска файлов используется функция НайтиФайлы. Проанализируем базовый подход к чтению через объект ТекстовыйДокумент.
Рассмотрим пример кода, который обходит файлы в папке и считывает их построчно:
МассивФайлов = НайтиФайлы("C:\sp\", "*.txt");
Текст = Новый ТекстовыйДокумент;
Для Каждого Файл Из МассивФайлов Цикл
Текст.Прочитать(Файл.ПолноеИмя);
Для НомерСтроки = 1 По Текст.КоличествоСтрок() Цикл
ТекущаяСтрока = Текст.ПолучитьСтроку(НомерСтроки);
// Здесь будет логика обработки строки
КонецЦикла;
КонецЦикла;
Важное замечание: Использование ТекстовыйДокумент удобно для небольших файлов. Однако, если файлы имеют огромный объем, метод Прочитать() загрузит всё содержимое в оперативную память сразу. В таких случаях мы рекомендуем использовать объект ЧтениеТекста, который позволяет считывать файл поток за потоком, что гораздо экономнее с точки зрения ресурсов сервера.
Допустим, наша строка имеет формат 1111-2222-3333-4444. Нам нужно извлечь первую часть для поиска документа, а остальные — для заполнения реквизитов. Самый эффективный способ сделать это в современных версиях платформы 1С:Предприятие 8.3 — использовать функцию СтрРазделить.
Давайте разберем, как разделить строку на части по дефису:
// Исходная строка из файла
ИсходнаяСтрока = "1111-2222-3333-4444";
// Разделяем строку, используя дефис в качестве разделителя
МассивЧастей = СтрРазделить(ИсходнаяСтрока, "-");
// Теперь мы можем обращаться к частям по индексу (начиная с 0)
Если МассивЧастей.Количество() >= 4 Тогда
Префикс = МассивЧастей[0]; // "1111"
Данные1 = МассивЧастей[1]; // "2222"
Данные2 = МассивЧастей[2]; // "3333"
Данные3 = МассивЧастей[3]; // "4444"
КонецЕсли;
Проанализируем ситуацию, когда длина префикса может меняться (например, иногда 4 символа, иногда 5 или 6). Использование функции Лев(Строка, 4) в этом случае будет ошибочным, так как она жестко привязана к количеству знаков. Метод СтрРазделить решает эту проблему автоматически: он заберет всё, что находится до первого дефиса, независимо от длины текста.
После того как мы получили префикс (например, "1111"), нам нужно найти документ, номер которого совпадает с этим значением. Для этого лучше всего использовать запрос. Выясним причину, почему это лучше прямого перебора: запрос работает на стороне сервера базы данных и возвращает только нужные ссылки, что в разы быстрее.
Посмотрим на пример запроса для поиска документа по номеру:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МойДокумент.Ссылка КАК Ссылка
|ИЗ
| Документ.МойДокумент КАК МойДокумент
|ГДЕ
| МойДокумент.Номер ПОДОБНО &НомерПоиска";
// Добавляем символ процента для поиска по частичному совпадению,
// если в 1С номера содержат ведущие нули или префиксы
Запрос.УстановитьПараметр("НомерПоиска", "%" + Префикс);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Нюанс с номерами документов: В 1С номера часто хранятся с ведущими нулями (например, "000000111"). Если в файле указано просто "111", прямое сравнение Номер = &Номер не сработает. Именно поэтому в параметре ПОДОБНО мы добавляем знак %. Также можно программно дополнить строку нулями до нужной длины, используя функцию Прав().
Когда ссылка на документ найдена, нам необходимо изменить его данные. Для этого нужно получить объект документа из ссылки с помощью метода ПолучитьОбъект().
Разберем процесс записи по шагам:
Пока Выборка.Следующий() Цикл
// Получаем объект для редактирования
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
// Заполняем реквизиты из нашего массива частей
ДокОбъект.Реквизит1 = МассивЧастей[1];
ДокОбъект.Реквизит2 = МассивЧастей[2];
ДокОбъект.Реквизит3 = МассивЧастей[3];
// Записываем изменения в базу данных
Попытка
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Исключение
Сообщить("Не удалось записать документ: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Если в вашем текстовом файле сотни или тысячи строк, выполнение запроса внутри цикла (как показано выше) крайне нежелательно. Это создаст избыточную нагрузку на сервер. Проанализируем, как сделать код профессиональным:
В (&МассивПрефиксов).НачатьТранзакцию() ... ЗафиксироватьТранзакцию(). Это ускорит запись в базу данных в несколько раз.Рассмотрим пример оптимизированного кода с проверкой границ массива:
// Проверка на корректность формата строки перед обращением к индексам
Если МассивЧастей.Количество() < 4 Тогда
Продолжить; // Пропускаем строку, если в ней недостаточно данных
КонецЕсли;
// Пример использования транзакции для массовой записи
НачатьТранзакцию();
Попытка
// Логика поиска и записи документов...
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка при массовой обработке: " + ОписаниеОшибки());
КонецПопытки;
Таким образом, мы построили надежный механизм: от безопасного чтения файла и гибкого парсинга строк с помощью СтрРазделить до эффективного поиска документов через запросы и их корректного обновления. Помните о проверке количества элементов в массиве после разделения строки, чтобы избежать ошибки "Индекс находится вне границ массива".