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

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При интеграции устаревших систем на платформе 1С:Предприятие 7.7 с современными веб-сервисами, CRM или другими базами данных часто возникает задача выгрузки информации в текстовые форматы, чаще всего в CSV (Comma-Separated Values). На первый взгляд задача кажется тривиальной: достаточно обойти выборку данных, склеить строки и записать их в файл. Однако разработчики часто сталкиваются с неприятной проблемой — в полученном файле после каждой заполненной строки появляется пустая строка. Это нарушает структуру файла и приводит к ошибкам при его чтении сторонними программами.

В данной статье мы подробно разберем, почему возникает этот эффект, как работает встроенный объект 1С 7.7 Текст, почему крайне важно очищать строки от концевых пробелов и какие альтернативные (и более современные) инструменты можно использовать для полного контроля над кодировкой и символами перевода строк.

Выясняем причину: почему двоится перевод строки?

Рассмотрим типичный код, который часто пишут начинающие разработчики (именно такой пример приводился в начале обсуждения):


ФайлCSV = СоздатьОбъект("Текст");
Выборка.ВыбратьСтроки();
Пока Выборка.ПолучитьСтроку() = 1 Цикл
    // Формируем строку и принудительно добавляем разделитель в конец
    СтрокаФайла = Выборка.Код + ";" + Выборка.Наименование + РазделительСтрок;
    ФайлCSV.ДобавитьСтроку(СтрокаФайла);
КонецЦикла;
ФайлCSV.Записать("C:\export.csv");

При просмотре полученного файла в обычном Блокноте мы увидим следующую картину:


00001;Товар 1

00002;Товар 2

00003;Товар 3

Кажется, что система добавила лишний пустой абзац. Почему так происходит? Дело в архитектуре работы встроенного объекта Текст в 1С 7.7.

Метод ДобавитьСтроку() не записывает данные в файл мгновенно. Он работает с оперативной памятью, добавляя переданное значение как новый элемент в виртуальный список (массив) строк. На этом этапе строка хранится внутри объекта "как есть".

Когда мы вызываем метод Записать(), платформа берет этот список строк и последовательно выгружает их на диск. При этом 1С 7.7 самостоятельно разделяет элементы списка стандартным для операционной системы Windows символом перевода строки — комбинацией CRLF (в шестнадцатеричном виде это байты 0x0D 0x0A, что соответствует функциям Симв(13) + Симв(10)).

Если в коде мы вручную прибавили к строке константу РазделительСтрок (которая в 1С 7.7 как раз и возвращает Симв(13) + Симв(10)), то при записи файла платформа добавит еще один системный перевод строки. В итоге в файле образуется последовательность CRLF CRLF. Любая программа-обработчик или текстовый редактор интерпретирует эту двойную последовательность как переход на новую строку и создание следующей пустой строки.

Решение проблемы: При использовании объекта Текст никогда не добавляйте в конец строки константу РазделительСтрок или символы Симв(13)+Симв(10) вручную. Метод ДобавитьСтроку() сделает все переводы автоматически при записи файла.

Правильный вариант кода выглядит так:


ФайлCSV = СоздатьОбъект("Текст");
Выборка.ВыбратьСтроки();
Пока Выборка.ПолучитьСтроку() = 1 Цикл
    // Собираем строку БЕЗ РазделительСтрок в конце
    СтрокаФайла = Выборка.Код + ";" + Выборка.Наименование;
    ФайлCSV.ДобавитьСтроку(СтрокаФайла);
КонецЦикла;
ФайлCSV.Записать("C:\export.csv");

Если вы откроете полученный таким образом файл в HEX-редакторе (редакторе шестнадцатеричных кодов), вы увидите, что в конце каждой строки гарантированно присутствуют байты 0D 0A, хотя в коде мы их явно не указывали. Платформа всё сделала за нас.

---

Очистка данных от пробелов: критическая важность функции СокрЛП

В сообщении №12 обсуждения прозвучал важный совет: использовать функцию СокрЛП() при выгрузке текстовых переменных. Давайте разберем подробнее, почему в среде 1С 7.7 пренебрежение этим правилом может испортить структуру CSV-файла.

В базах данных 1С 7.7 (особенно DBF-версиях) текстовые реквизиты справочников и документов имеют жестко заданную фиксированную длину. Например, длина наименования номенклатуры в конфигурации может составлять 100 символов. Если реальное название товара занимает всего 15 символов (например, "Кабель силовой"), то оставшиеся 85 символов физически заполняются пробелами в базе данных.

Если мы попытаемся выгрузить этот реквизит напрямую без обработки:

СтрокаФайла = Выборка.Код + ";" + Выборка.Наименование + ";" + Выборка.Цена;

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


00015;Кабель силовой                                                                                     ;1500.00

Это приводит к следующим негативным последствиям:

  1. Размер файла: Размер итогового CSV-файла увеличивается в разы (иногда в десятки раз) исключительно за счет невидимых "пустых" пробелов.
  2. Ошибки импорта: Приемные системы (например, интернет-магазины на PHP/Python или базы данных SQL) импортируют эти пробелы внутрь своих таблиц. Поиск по наименованию в таких системах станет невозможен, пока данные не будут очищены.

Поэтому всегда очищайте текстовые поля с помощью функции СокрЛП(), которая удаляет все незначащие пробелы слева и справа от полезного текста:


СтрокаФайла = СокрЛП(Выборка.Код) + ";" + СокрЛП(Выборка.Наименование) + ";" + СокрЛП(Выборка.Цена);

---

Формирование валидного CSV: экранирование кавычек и спецсимволов

Простое объединение строк через точку с запятой (;) таит в себе еще одну опасность. Если в самом наименовании товара встретится символ-разделитель (например, точка с запятой в названии: "Комплект подключения; тип А") или символ кавычки, структура файла CSV безвозвратно нарушится при чтении.

По правилам формата CSV (RFC 4180):

Рассмотрим, как написать вспомогательную функцию для подготовки текста перед записью в CSV:


Функция ПодготовитьДляCSV(Знач ТекстПоля)
    Перем Рез;
    Рез = СокрЛП(Строка(ТекстПоля));
    
    // Если в тексте есть кавычки, удваиваем их
    Если Найти(Рез, """") > 0 Тогда
        Рез = СтрЗаменить(Рез, """", """""");
    КонецЕсли;
    
    // Если есть разделитель или кавычки, оборачиваем все поле в кавычки
    Если (Найти(Рез, ";") > 0) Или (Найти(Рез, """") > 0) Или (Найти(Рез, Симв(10)) > 0) Тогда
        Рез = """" + Рез + """";
    КонецЕсли;
    
    Возврат Рез;
КонецФункции

Теперь процесс формирования строки выгрузки станет абсолютно безопасным и надежным:


СтрокаФайла = ПодготовитьДляCSV(Выборка.Код) + ";" + ПодготовитьДляCSV(Выборка.Наименование) + ";" + ПодготовитьДляCSV(Выборка.Цена);
ФайлCSV.ДобавитьСтроку(СтрокаФайла);

---

Альтернативные способы записи файлов (когда стандартного объекта "Текст" недостаточно)

Хотя стандартный объект 1С 7.7 Текст прост в использовании, он имеет два серьезных ограничения:

  1. Ограничение по кодировкам: Он поддерживает только две кодировки: Windows (ANSI / CP1251) и DOS (OEM / CP866). Записать файл в современной и повсеместно требуемой кодировке UTF-8 напрямую через него невозможно.
  2. Принудительный перевод в конце файла: Метод Записать() всегда автоматически ставит перевод строки (CRLF) в самый конец файла после последней строки. Для некоторых строгих систем интеграции наличие пустого перевода в конце файла недопустимо.

Для решения этих проблем мы можем использовать системные COM-объекты операционной системы Windows.

Вариант А. Запись через Scripting.FileSystemObject (FSO)

Этот способ предоставляет низкоуровневый доступ к записи файлов. Он позволяет вручную управлять каждым байтом перевода строк и не добавлять ничего лишнего в конец файла. Мы используем метод Write(), который записывает текст строго "как есть" (без автоматического добавления перевода строки в отличие от метода WriteLine()).

Рассмотрим пример реализации:


// Создаем объект для работы с файловой системой Windows
ФС_Объект = СоздатьОбъект("Scripting.FileSystemObject");

// Открываем файл для записи (Путь, Режим: 2 - запись, ФлагСоздания: Истина)
// Последний параметр: 0 - ASCII (ANSI), -1 - Unicode (UTF-16), -2 - Системная кодировка по умолчанию
НовыйФайл = ФС_Объект.CreateTextFile("C:\temp\export_fso.csv", 1, 0); 

Выборка.ВыбратьСтроки();
ПерваяСтрока = 1;

Пока Выборка.ПолучитьСтроку() = 1 Цикл
    // Формируем строку данных
    ТекущаяСтрока = ПодготовитьДляCSV(Выборка.Код) + ";" + ПодготовитьДляCSV(Выборка.Наименование);
    
    // Перевод строки добавляем только ПЕРЕД следующей строкой, 
    // чтобы избежать лишнего символа перевода строки в самом конце файла
    Если ПерваяСтрока = 1 Тогда
        ПерваяСтрока = 0;
    Иначе
        НовыйФайл.Write(РазделительСтрок);
    КонецЕсли;
    
    НовыйФайл.Write(ТекущаяСтрока);
КонецЦикла;

НовыйФайл.Close();

Вариант Б. Запись в формате UTF-8 через ADODB.Stream

Если веб-сайт или внешняя база данных требует от нас выгрузку исключительно в кодировке UTF-8, то использование ActiveX-объекта ADODB.Stream — это лучшее и самое быстрое решение, не требующее сторонних внешних компонент.

Проанализируем пример кода для экспорта в UTF-8:


Поток = СоздатьОбъект("ADODB.Stream");
Поток.Type = 2; // Указываем, что работаем с текстовыми данными (text stream)
Поток.Charset = "utf-8"; // Задаем целевую кодировку выгрузки
Поток.Open();

Выборка.ВыбратьСтроки();
Пока Выборка.ПолучитьСтроку() = 1 Цикл
    ТекущаяСтрока = ПодготовитьДляCSV(Выборка.Код) + ";" + ПодготовитьДляCSV(Выборка.Наименование);
    
    // Метод WriteText имеет второй параметр:
    // 0 - записать без перевода строки
    // 1 - записать строку и автоматически добавить системный разделитель (CRLF) в конец
    Поток.WriteText(ТекущаяСтрока, 1);
КонецЦикла;

// Сохраняем поток в файл на диске
// Параметр 2 означает "Перезаписать файл, если он уже существует"
Поток.SaveToFile("C:\temp\export_utf8.csv", 2);
Поток.Close();

Использование ADODB.Stream гарантирует, что файл будет сохранен в полноценном стандарте UTF-8 (по умолчанию с BOM-сигнатурой, что упрощает распознавание кодировки текстовыми редакторами типа Excel).

---

Резюме и практические рекомендации

Подведем итоги нашего исследования по выгрузке текстовых файлов из 1С:Предприятия 7.7:

  1. При использовании встроенного объекта Текст помните, что метод ДобавитьСтроку() разделяет элементы списка автоматически при вызове метода Записать(). Никогда не добавляйте РазделительСтрок вручную.
  2. Текстовые реквизиты в 1С 7.7 часто дополняются пробелами до полной длины поля. Всегда используйте СокрЛП() для предотвращения раздувания размера файлов и порчи структуры таблиц.
  3. Для качественного формирования CSV-файлов обязательно экранируйте спецсимволы и кавычки. Используйте для этого специализированные вспомогательные функции.
  4. Если вам требуется выгрузка в кодировке UTF-8 или необходим строгий контроль над каждым символом перевода строки в конце файла — откажитесь от встроенного объекта Текст в пользу внешних COM-объектов Windows: Scripting.FileSystemObject или ADODB.Stream.
← На главную