При разработке алгоритмов выгрузки данных программисты часто сталкиваются с ситуацией, когда вместо ожидаемого списка строк в итоговый файл попадает только одна — самая последняя. Это происходит из-за типичной логической ошибки: перезаписи переменной на каждой итерации цикла вместо добавления (аккумуляции) новых данных. Рассмотрим подробно, почему так происходит и как реализовать корректную запись данных несколькими способами.
Разберем ситуацию на примере исходного кода. Когда внутри цикла Пока Выборка.Следующий() используется конструкция Данные2 = выборка.данные3;, система на каждом шаге стирает старое значение переменной Данные2 и записывает туда новое. В итоге после завершения цикла в переменной остается только результат последней итерации.
Для решения этой задачи нам необходимо либо накапливать текст в промежуточной переменной, либо записывать строку непосредственно в объект текстового документа прямо внутри цикла.
Проанализируем самый простой вариант, когда нам нужно собрать одну большую строку и передать её куда-то дальше. Чтобы данные не склеивались в одну «кашу», мы должны использовать специальные символы переноса строки.
Рассмотрим пример кода, где мы добавляем проверку на заполненность, чтобы не начинать файл с пустой строки:
Данные2 = "";
Пока Выборка.Следующий() Цикл
Если ЗначениеЗаполнено(Данные2) Тогда
// Добавляем символ переноса строки перед новой порцией данных
Данные2 = Данные2 + Символы.ПС + Выборка.Данные3;
Иначе
// Если это первая итерация, просто присваиваем значение
Данные2 = Выборка.Данные3;
КонецЕсли;
КонецЦикла;
В данном примере Символы.ПС — это системная константа, обозначающая перевод строки. В некоторых случаях (например, для корректного отображения в старом «Блокноте» Windows) может потребоваться Символы.ВКПС (возврат каретки и перевод строки).
Объект ТекстовыйДокумент удобен тем, что он инкапсулирует в себе логику работы со строками. Нам не нужно вручную добавлять Символы.ПС, так как метод ДобавитьСтроку() делает это автоматически.
Выясним, как изменить структуру функции, чтобы цикл находился внутри процесса формирования документа:
ТД = Новый ТекстовыйДокумент;
Данные1 = "Заголовок или постоянная часть";
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Формируем строку для каждой итерации
ТекущаяСтрока = Данные1 + ";" + Выборка.Данные3;
// Добавляем её в объект текстового документа
ТД.ДобавитьСтроку(ТекущаяСтрока);
КонецЦикла;
// Сохраняем весь накопленный результат на диск
ТД.Записать(ИмяФайла, КодировкаТекста.UTF8);
Важный момент: использование ТекстовыйДокумент оправдано для небольших и средних объемов данных. Поскольку этот объект хранит весь текст в оперативной памяти, при выгрузке сотен тысяч строк программа может начать потреблять слишком много ресурсов.
Для создания больших файлов или логов профессионалы рекомендуют использовать объект ЗаписьТекста. Он работает в потоковом режиме: данные сбрасываются на диск порциями, что значительно экономит память.
Разберем по шагам, как реализовать дозапись в файл:
ЗаписьТекста, указывая путь к файлу и кодировку.Дописывать = Истина, если нужно добавить данные в конец существующего файла.ЗаписатьСтроку().Закрыть(), чтобы зафиксировать изменения на диске.
ПутьКФайлу = "C:\temp\log.txt";
// Третий параметр "Истина" включает режим дозаписи
Запись = Новый ЗаписьТекста(ПутьКФайлу, КодировкаТекста.UTF8, , Истина);
Пока Выборка.Следующий() Цикл
ТекстДляЗаписи = Строка(Выборка.Данные3);
Запись.ЗаписатьСтроку(ТекстДляЗаписи);
КонецЦикла;
Запись.Закрыть();
Рассмотрим подробнее ситуации, когда стандартных методов может быть недостаточно:
1. Использование массива для сборки строк. Если вам все же нужно собрать данные в одну переменную-строку, но итераций очень много (тысячи), классическая конкатенация через + будет работать медленно. Проанализируем более эффективный подход через Массив:
МассивСтрок = Новый Массив;
Пока Выборка.Следующий() Цикл
МассивСтрок.Добавить(Строка(Выборка.Данные3));
КонецЦикла;
ИтоговыйТекст = СтрСоединить(МассивСтрок, Символы.ПС);
Этот метод работает в разы быстрее, так как 1С не пересоздает строку в памяти на каждом шаге цикла.
2. Типизация данных. Всегда явно преобразуйте значения к строке, используя функцию Строка(). Если в Выборка.Данные3 окажется число (например, 1 000), 1С может добавить неразрывный пробел в качестве разделителя разрядов, что нарушит структуру CSV-файла или XML. Для чисел лучше использовать Формат(Значение, "ЧГ=0").
3. Формирование XML. Если переменная называется ТекстXML, как в исходном вопросе, лучше вообще отказаться от ручной склейки строк. Для этих целей в платформе есть специализированный объект ЗаписьXML. Он автоматически следит за корректностью спецсимволов (заменяет & на & и т.д.) и закрытием тегов, что гарантирует валидность вашего файла.
Таким образом, выбор метода зависит от вашей задачи: для простых отчетов подойдет ТекстовыйДокумент, для высоконагруженных систем — ЗаписьТекста, а для сборки строк в памяти — Массив и СтрСоединить.