Запись таблицы значений на диск: CSV, Excel, MXL и XML с примерами кода
Содержание
Сохранить таблицу значений в файл в 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 Тогда
Текст = """" + СтрЗаменить(Текст, """", """""") + """";
КонецЕсли;
Возврат Текст;
КонецФункции
Что здесь сделано и зачем:
- Числа форматируются с
ЧГ=0— без пробелов между разрядами. Иначе1 250,50Excel прочитает как текст. ЧН=0выводит ноль цифрой. Без него нулевая сумма станет пустой ячейкой.- Даты пишутся как
dd.MM.yyyy. Нужно время — поставьтеДФ='dd.MM.yyyy HH:mm:ss'. - Кавычки внутри текста удваиваются:
ООО "Ромашка"превращается в"ООО ""Ромашка""". Это стандартное экранирование 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 / TXT | Excel, любые программы | нет, всё текст | обмен с внешними системами, банком, сайтом |
| XLSX | Excel, 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С. В файловом варианте сервер и клиент — один компьютер, поэтому проблема всплывает только после перехода на клиент-серверную базу
.
Правильная схема для управляемой формы:
- На сервере записать файл во временный каталог.
- Прочитать его в двоичные данные и положить во временное хранилище.
- На клиенте получить файл из хранилища на диск пользователя.
&НаСервере
Функция ПодготовитьФайлНаСервере()
ТЗ = ПолучитьДанныеДляВыгрузки(); // ваша функция, возвращает таблицу значений
ИмяВременного = ПолучитьИмяВременногоФайла("xlsx");
ТаблицаВТабличныйДокумент(ТЗ).Записать(ИмяВременного, ТипФайлаТабличногоДокумента.XLSX);
Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяВременного), УникальныйИдентификатор);
УдалитьФайлы(ИмяВременного);
Возврат Адрес;
КонецФункции
&НаКлиенте
Процедура Выгрузить(Команда)
Адрес = ПодготовитьФайлНаСервере();
ПолучитьФайл(Адрес, "Остатки.xlsx", Истина);
КонецПроцедуры
ПолучитьФайл() — синхронный метод. В конфигурациях, где в свойствах указан режим использования синхронных вызовов «Не использовать», он вызовет ошибку. Там берут асинхронный НачатьПолучениеФайлаССервера() или, в типовых на БСП, ФайловаяСистемаКлиент.СохранитьФайл(). Порядок параметров у них разный, сверьтесь с синтакс-помощником.
Вариант без возни с файлами: показать табличный документ пользователю (ТабДок.Показать("Остатки")). В открывшемся окне он сам сохранит его в XLSX, PDF или MXL кнопкой сохранения.
Если таблица уже на форме
Когда таблица значений выведена реквизитом на управляемую форму, программировать вообще ничего не нужно. В командной панели таблицы нажмите Ещё → Вывести список…, отметьте нужные колонки и нажмите «ОК». Откроется табличный документ — его сохраняют в Excel через Файл → Сохранить как или кнопку дискеты.
7. Ошибки записи и права доступа
Почти все сбои при записи файла сводятся к трём вещам: путь, права, безопасный режим. Оборачивайте запись в Попытка … Исключение, чтобы пользователь увидел понятное сообщение, а в журнал регистрации попало подробное:
Попытка
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
Исключение
ЗаписьЖурналаРегистрации("Выгрузка таблицы", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось сохранить файл " + ИмяФайла + ". Проверьте путь и права на каталог.";
КонецПопытки;
Разбор типичных ситуаций:
Не выдавайте учётной записи сервера 1С права на запись в корень диска или системные каталоги ради выгрузки. Заведите отдельную папку и дайте права только на неё.
Отдельный случай — большие таблицы. Табличный документ держит все ячейки в памяти, и на сотнях тысяч строк серверный процесс может съесть гигабайты. Для таких объёмов пишите CSV построчно: ЗаписьТекста не копит данные и расходует память только на текущую строку.
Частые вопросы
Сколько строк можно выгрузить в XLSX?
Как сохранить таблицу значений в JSON?
ЗаписатьJSON() таблицу значений не принимает. Преобразуйте её в массив структур: для каждой строки создайте структуру с ключами-именами колонок, затем запишите массив через ЗаписьJSON. Ссылки предварительно переведите в строки.Можно ли сохранить таблицу значений в файл прямо из отладчика?
ЗначениеВФайл("C:\Temp\тз.txt", ТЗ). Если точка останова стоит в серверном коде, файл окажется на сервере.Чем MXL отличается от XLSX при сохранении табличного документа?
Как добавить данные в уже существующий CSV, а не перезаписать его?
ЗаписьТекста есть параметр дописывания. Передайте в нём Истина, и новые строки встанут в конец файла. Шапку при этом повторно не пишите.