Запись таблицы значений на диск: CSV, Excel, MXL и XML с примерами кода

· 10 мин

Содержание

Сохранить таблицу значений в файл в 1С 8.3 можно четырьмя путями. Для обмена и Excel берут CSV через ЗаписьТекста или XLSX через ТабличныйДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX). Чтобы потом прочитать таблицу обратно в 1С без потерь, используют ЗначениеВФайл() или XML через СериализаторXDTO.

Всё это — механизмы платформы, они одинаково работают в БП 3.0, ЗУП 3.1, УТ 11 и в самописных конфигурациях. Главная развилка не в конфигурации, а в том, где выполняется код: на сервере файл пишется на диск сервера, а не на компьютер пользователя.

1. Подготовка таблицы значений к записи

Файл получится ровно таким, какой была таблица в момент записи. Поэтому порядок наводят до выгрузки, а не в Excel.

Что проверить:

  • 🔤 Заголовки колонок. У каждой колонки есть Имя (латиница или кириллица без пробелов) и Заголовок (человеческое название). В шапку файла лучше писать заголовок.
  • 🔢 Типы. Колонка без типа принимает что угодно: в одной строке число, в другой строка. В Excel такая колонка не посчитается.
  • 🔗 Ссылки. Ссылка на справочник в файле превращается в представление — наименование. Код или ИНН при этом теряются. Нужен код — заведите отдельную колонку.
  • 🧹 Лишние колонки и строки. Служебные колонки удалите ТЗ.Колонки.Удалить("ИмяКолонки"), свёртку сделайте ТЗ.Свернуть("Номенклатура", "Количество, Сумма"), порядок — ТЗ.Сортировать("Номенклатура").

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

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)), "Номенклатура");
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)), "Кол-во");
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)), "Сумма, руб.");
ТЗ.Колонки.Добавить("ДатаПоступления", Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)), "Дата поступления");

Если таблица пришла из запроса через Запрос.Выполнить().Выгрузить(), типы колонок уже заданы. Ссылки удобнее сразу превратить в строки в самом запросе: ПРЕДСТАВЛЕНИЕ(Остатки.Номенклатура) КАК Номенклатура, а код получить отдельным полем Остатки.Номенклатура.Код КАК Код.

Заголовки колонок из запроса совпадают с псевдонимами полей. Задайте псевдонимы по-русски и без сокращений — и шапка файла будет читаемой без доработки.

2. Как выгрузить таблицу значений в CSV и TXT

CSV — самый простой и переносимый вариант. Его открывает Excel, LibreOffice, банковские и складские программы. Пишут его объектом ЗаписьТекста построчно.

Универсальная процедура для общего модуля или модуля обработки:

Процедура ЗаписатьТаблицуВCSV(ТЗ, ИмяФайла, Разделитель = ";") Экспорт

	Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);

	Шапка = Новый Массив;
	Для Каждого Колонка Из ТЗ.Колонки Цикл
		Заголовок = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок);
		Шапка.Добавить(ПолеCSV(Заголовок, Разделитель));
	КонецЦикла;
	Запись.ЗаписатьСтроку(СтрСоединить(Шапка, Разделитель));

	Для Каждого СтрокаТЗ Из ТЗ Цикл
		Поля = Новый Массив;
		Для Каждого Колонка Из ТЗ.Колонки Цикл
			Поля.Добавить(ПолеCSV(СтрокаТЗ[Колонка.Имя], Разделитель));
		КонецЦикла;
		Запись.ЗаписатьСтроку(СтрСоединить(Поля, Разделитель));
	КонецЦикла;

	Запись.Закрыть();

КонецПроцедуры

Функция ПолеCSV(Значение, Разделитель)

	ТипЗначения = ТипЗнч(Значение);
	Если ТипЗначения = Тип("Число") Тогда
		Текст = Формат(Значение, "ЧРД=,; ЧГ=0; ЧН=0");
	ИначеЕсли ТипЗначения = Тип("Дата") Тогда
		Текст = Формат(Значение, "ДФ=dd.MM.yyyy");
	ИначеЕсли ТипЗначения = Тип("Булево") Тогда
		Текст = ?(Значение, "Да", "Нет");
	Иначе
		Текст = Строка(Значение);
	КонецЕсли;

	// Поле с разделителем, кавычкой или переносом строки берём в кавычки
	Если СтрНайти(Текст, Разделитель) > 0
		Или СтрНайти(Текст, """") > 0
		Или СтрНайти(Текст, Символы.ПС) > 0 Тогда
		Текст = """" + СтрЗаменить(Текст, """", """""") + """";
	КонецЕсли;

	Возврат Текст;

КонецФункции

Что здесь сделано и зачем:

  1. Числа форматируются с ЧГ=0 — без пробелов между разрядами. Иначе 1 250,50 Excel прочитает как текст.
  2. ЧН=0 выводит ноль цифрой. Без него нулевая сумма станет пустой ячейкой.
  3. Даты пишутся как dd.MM.yyyy. Нужно время — поставьте ДФ='dd.MM.yyyy HH:mm:ss'.
  4. Кавычки внутри текста удваиваются: ООО "Ромашка" превращается в "ООО ""Ромашка""". Это стандартное экранирование CSV.

Вызов: ЗаписатьТаблицуВCSV(ТЗ, "C:\Выгрузка\остатки.csv").

TXT с табуляцией

Плоский текстовый файл с разделителем-табуляцией пишется той же процедурой: ЗаписатьТаблицуВCSV(ТЗ, "C:\Выгрузка\остатки.txt", Символы.Таб). Табуляция почти не встречается в наименованиях, поэтому кавычки срабатывают редко. Такой файл удобно вставлять в Excel через буфер обмена.

3. Запись таблицы значений в Excel (XLSX)

Excel-файл в 1С 8.3 делают через табличный документ. Сначала таблицу значений переносят в ТабличныйДокумент, затем вызывают Записать() с типом XLSX. Сам Excel на сервере при этом не нужен.

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

Функция ТаблицаВТабличныйДокумент(ТЗ) Экспорт

	ТабДок = Новый ТабличныйДокумент;
	ЖирныйШрифт = Новый Шрифт(, , Истина);

	НомКол = 0;
	Для Каждого Колонка Из ТЗ.Колонки Цикл
		НомКол = НомКол + 1;
		Область = ТабДок.Область(1, НомКол, 1, НомКол);
		Область.Текст = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок);
		Область.Шрифт = ЖирныйШрифт;
	КонецЦикла;

	НомСтр = 1;
	Для Каждого СтрокаТЗ Из ТЗ Цикл
		НомСтр = НомСтр + 1;
		НомКол = 0;
		Для Каждого Колонка Из ТЗ.Колонки Цикл
			НомКол = НомКол + 1;
			Область = ТабДок.Область(НомСтр, НомКол, НомСтр, НомКол);
			Область.СодержитЗначение = Истина;
			Область.ТипЗначения = Колонка.ТипЗначения;
			Область.Значение = СтрокаТЗ[Колонка.Имя];
		КонецЦикла;
	КонецЦикла;

	Возврат ТабДок;

КонецФункции

Запись на диск:

ТабДок = ТаблицаВТабличныйДокумент(ТЗ);
ТабДок.Записать("C:\Выгрузка\остатки.xlsx", ТипФайлаТабличногоДокумента.XLSX);

Почему ячейки заполняются через Значение, а не через Текст: при записи в Текст всё уходит в Excel строками. Сумма выглядит числом, но СУММ() по колонке даёт ноль. Значение с типом сохраняет числа числами, а даты датами.

Короткий вариант через построитель отчёта

Для разовой выгрузки хватает трёх строк:

Построитель = Новый ПостроительОтчета;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);
ТабДок = Новый ТабличныйДокумент;
Построитель.Вывести(ТабДок);
ТабДок.Записать("C:\Выгрузка\остатки.xlsx", ТипФайлаТабличногоДокумента.XLSX);

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

Не используйте COM-объект Excel.Application для простой выгрузки. Он требует установленного Excel на той машине, где выполняется код, не работает на Linux-сервере и медленный: десятки тысяч строк через COM пишутся минутами.

Ширина колонок и автофильтр

Табличный документ сохраняет в XLSX ширину колонок и шрифты. Ширину задают для области колонки: ТабДок.Область(, НомКол, , НомКол).ШиринаКолонки = 30. Строку шапки удобно закрепить, установив ТабДок.ФиксацияСверху = 1.

4. Формат MXL и сохранение «как есть» для самой 1С

Если файл будет открывать только 1С, Excel не нужен. Здесь два сценария.

MXL — табличный документ в родном формате

ТабДок.Записать("C:\Выгрузка\остатки.mxl", ТипФайлаТабличногоДокумента.MXL);

MXL сохраняет всё оформление табличного документа один в один: объединения, рамки, расшифровки. Открывается в любой 1С 8.3 через меню Файл → Открыть. Формат удобен для архива печатных форм и отчётов, но обработать его в Excel без 1С нельзя.

Таблица целиком, со всеми типами

Когда нужно сохранить именно таблицу значений, а потом загрузить её обратно с теми же колонками и типами, используйте сериализацию:

// Сохранить
ЗначениеВФайл("C:\Выгрузка\тз.txt", ТЗ);

// Прочитать обратно
ТЗ = ЗначениеИзФайла("C:\Выгрузка\тз.txt");

ЗначениеВФайл() доступна на сервере и в толстом клиенте. В тонком клиенте её нет — вызывайте из серверной процедуры.

Если файл должна прочитать другая база или внешняя система, лучше XML:

ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Выгрузка\тз.xml", "UTF-8");
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТЗ, НазначениеТипаXML.Явное);
ЗаписьXML.Закрыть();

Чтение обратно — ЧтениеXML.ОткрытьФайл() и СериализаторXDTO.ПрочитатьXML(ЧтениеXML).

СпособКто открываетТипы сохраняютсяКогда брать
CSV / TXTExcel, любые программынет, всё текстобмен с внешними системами, банком, сайтом
XLSXExcel, LibreOfficeда, числа и датыотчёт для человека
MXLтолько 1Соформление даархив отчётов и печатных форм
ЗначениеВФайлтолько 1Сполностьювременное сохранение и загрузка обратно
XML (XDTO)1С, внешние системыполностьюобмен между базами

Ссылки на справочники и документы в ЗначениеВФайл и XML пишутся как уникальные идентификаторы. В другой базе такая ссылка превратится в «битую», если объекта с тем же идентификатором там нет.

5. Кодировка и разделитель: почему файл открывается кракозябрами

Почти все жалобы на «сломанный» CSV — это кодировка или разделитель, а не данные.

Кодировка. КодировкаТекста.UTF8 записывает в начало файла метку BOM. По ней современный Excel понимает, что текст в UTF-8, и кириллица видна нормально. Старые программы и некоторые банк-клиенты ждут Windows-1251 — для них пишите с КодировкаТекста.ANSI.

Если принимающая сторона требует UTF-8 без BOM, соберите текст в строку и запишите двоичными данными:

Данные = ПолучитьДвоичныеДанныеИзСтроки(ТекстФайла, КодировкаТекста.UTF8, Ложь);
Данные.Записать("C:\Выгрузка\выгрузка.csv");

Третий параметр Ложь отключает запись BOM.

Разделитель. Excel с русскими региональными настройками ждёт точку с запятой, потому что запятая занята под десятичный разделитель. Отсюда правило:

ПолучательРазделитель полейДесятичный разделитель
Excel с русской локалью;, (ЧРД=,)
Внешняя система, API, Python, или по ТЗ. (ЧРД=.)
Вставка через буфертабуляция,

Переносы строк. ЗаписьТекста по умолчанию пишет перевод строки в стиле Windows. Если нужен формат Linux, передайте нужный разделитель строк в конструктор — параметры описаны в синтакс-помощнике у объекта ЗаписьТекста.

Excel при открытии CSV двойным щелчком сам решает, что считать датой. Артикул 03-12 превратится в 3 декабря, а длинный код — в 1,23E+15. Если такие колонки есть, отдавайте пользователю XLSX, а не CSV.

6. Как передать сохранённый файл с сервера пользователю

Частая ловушка: код в процедуре с директивой &НаСервере пишет C:\Выгрузка\остатки.xlsx, файл создаётся без ошибок, но у пользователя его нет. Он лёг на диск сервера 1С. В файловом варианте сервер и клиент — один компьютер, поэтому проблема всплывает только после перехода на клиент-серверную базу .

Правильная схема для управляемой формы:

  1. На сервере записать файл во временный каталог.
  2. Прочитать его в двоичные данные и положить во временное хранилище.
  3. На клиенте получить файл из хранилища на диск пользователя.
&НаСервере
Функция ПодготовитьФайлНаСервере()

	ТЗ = ПолучитьДанныеДляВыгрузки(); // ваша функция, возвращает таблицу значений
	ИмяВременного = ПолучитьИмяВременногоФайла("xlsx");
	ТаблицаВТабличныйДокумент(ТЗ).Записать(ИмяВременного, ТипФайлаТабличногоДокумента.XLSX);

	Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяВременного), УникальныйИдентификатор);
	УдалитьФайлы(ИмяВременного);
	Возврат Адрес;

КонецФункции

&НаКлиенте
Процедура Выгрузить(Команда)

	Адрес = ПодготовитьФайлНаСервере();
	ПолучитьФайл(Адрес, "Остатки.xlsx", Истина);

КонецПроцедуры

ПолучитьФайл() — синхронный метод. В конфигурациях, где в свойствах указан режим использования синхронных вызовов «Не использовать», он вызовет ошибку. Там берут асинхронный НачатьПолучениеФайлаССервера() или, в типовых на БСП, ФайловаяСистемаКлиент.СохранитьФайл(). Порядок параметров у них разный, сверьтесь с синтакс-помощником.

Вариант без возни с файлами: показать табличный документ пользователю (ТабДок.Показать("Остатки")). В открывшемся окне он сам сохранит его в XLSX, PDF или MXL кнопкой сохранения.

Если таблица уже на форме

Когда таблица значений выведена реквизитом на управляемую форму, программировать вообще ничего не нужно. В командной панели таблицы нажмите Ещё → Вывести список…, отметьте нужные колонки и нажмите «ОК». Откроется табличный документ — его сохраняют в Excel через Файл → Сохранить как или кнопку дискеты.

7. Ошибки записи и права доступа

Почти все сбои при записи файла сводятся к трём вещам: путь, права, безопасный режим. Оборачивайте запись в Попытка … Исключение, чтобы пользователь увидел понятное сообщение, а в журнал регистрации попало подробное:

Попытка
	ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
Исключение
	ЗаписьЖурналаРегистрации("Выгрузка таблицы", УровеньЖурналаРегистрации.Ошибка, , ,
		ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	ВызватьИсключение "Не удалось сохранить файл " + ИмяФайла + ". Проверьте путь и права на каталог.";
КонецПопытки;

Разбор типичных ситуаций:

Диагностика: выберите симптом

Не выдавайте учётной записи сервера 1С права на запись в корень диска или системные каталоги ради выгрузки. Заведите отдельную папку и дайте права только на неё.

Отдельный случай — большие таблицы. Табличный документ держит все ячейки в памяти, и на сотнях тысяч строк серверный процесс может съесть гигабайты. Для таких объёмов пишите CSV построчно: ЗаписьТекста не копит данные и расходует память только на текущую строку.

Частые вопросы

Сколько строк можно выгрузить в XLSX?
Ограничение со стороны Excel — 1 048 576 строк на листе. Платформа запишет и больше, но Excel откроет файл не полностью. Для больших объёмов используйте CSV.
Как сохранить таблицу значений в JSON?
Напрямую ЗаписатьJSON() таблицу значений не принимает. Преобразуйте её в массив структур: для каждой строки создайте структуру с ключами-именами колонок, затем запишите массив через ЗаписьJSON. Ссылки предварительно переведите в строки.
Можно ли сохранить таблицу значений в файл прямо из отладчика?
Да. В окне вычисления выражения выполните ЗначениеВФайл("C:\Temp\тз.txt", ТЗ). Если точка останова стоит в серверном коде, файл окажется на сервере.
Чем MXL отличается от XLSX при сохранении табличного документа?
MXL хранит все возможности табличного документа 1С, включая расшифровки и макеты. XLSX — переносимый формат для Excel: часть оформления 1С в нём теряется, зато файл открывается без 1С.
Как добавить данные в уже существующий CSV, а не перезаписать его?
У конструктора ЗаписьТекста есть параметр дописывания. Передайте в нём Истина, и новые строки встанут в конец файла. Шапку при этом повторно не пишите.