Смена расширения и формата файла кодом 1С:Предприятия 8.3

· 9 мин

Содержание

Чтобы изменить расширение файла в 1С, соберите новое имя из свойств объекта Файл (Путь + ИмяБезРасширения + новое расширение) и вызовите ПереместитьФайл(СтароеИмя, НовоеИмя). Отдельного метода «сменить расширение» в платформе 1С:Предприятие 8.3 нет: переименование и перемещение делает одна функция. В тонком клиенте на платформе 8.3.18 и новее используйте асинхронный вариант ПереместитьФайлАсинх.

Учтите главное: новое расширение не меняет содержимое. Если отчет.mxl переименовать в отчет.xlsx, Excel его не откроет. Для настоящей смены формата файл нужно перезаписать: табличный документ — методом Записать с другим типом файла, текст — с нужной кодировкой, произвольные данные — через ДвоичныеДанные.

Как платформа 1С работает с файлами и где выполняется код

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

Где выполняется кодЧей диск доступенПод какой учётной записью
&НаСервере, фоновое задание (клиент-серверная база)диск сервера 1Спользователь службы сервера 1С
&НаСервере в файловой базедиск компьютера пользователяпользователь Windows
&НаКлиенте, тонкий клиентдиск компьютера пользователяпользователь Windows
&НаКлиенте, веб-клиенттолько через расширение для работы с файламипользователь браузера

Отсюда типичная путаница. Разработчик пишет ПереместитьФайл("C:\Выгрузка\data.txt", ...) в серверной процедуре, а файл лежит на машине бухгалтера. Сервер ищет его у себя на диске C: и падает с ошибкой.

Объект Файл даёт разобрать имя без ручной работы со строками:

  • 📄 Имя — имя с расширением: data.txt;
  • 🏷️ ИмяБезРасширения — data;
  • 🔖 Расширение — с точкой: .txt;
  • 📁 Путь — каталог с завершающим разделителем: C:\Выгрузка\;
  • 🧭 ПолноеИмя — всё вместе.

У файла backup.tar.gz свойство Расширение вернёт только .gz, а ИмяБезРасширения — backup.tar. Если нужно заменить двойное расширение, обрежьте строку сами.

Для веб-клиента сначала подключите расширение работы с файлами: в 8.3.18+ это Ждать ПодключитьРасширениеРаботыСФайламиАсинх(). Без него методы прямого доступа к диску пользователя недоступны.

Способы изменить расширение файла средствами встроенного языка

Начните с функции, которая строит новое имя. Её удобно держать в общем модуле с флагами «Клиент» и «Сервер»:

Функция ИмяСДругимРасширением(ПолноеИмя, НовоеРасширение) Экспорт

	Файл = Новый Файл(ПолноеИмя);
	Расширение = СокрЛП(НовоеРасширение);

	Если Не ПустаяСтрока(Расширение) И Лев(Расширение, 1) <> "." Тогда
		Расширение = "." + Расширение;
	КонецЕсли;

	Возврат Файл.Путь + Файл.ИмяБезРасширения + Расширение;

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

Пустая строка в НовоеРасширение даст имя без расширения вовсе. Это тоже рабочий сценарий.

Способ 1. Переименовать на месте: ПереместитьФайл

На сервере или в толстом клиенте хватит синхронного вызова:

&НаСервереБезКонтекста
Процедура СменитьРасширениеНаСервере(ПолноеИмя)

	НовоеИмя = ИмяСДругимРасширением(ПолноеИмя, "csv");

	Если (Новый Файл(НовоеИмя)).Существует() Тогда
		ВызватьИсключение "Файл " + НовоеИмя + " уже существует";
	КонецЕсли;

	ПереместитьФайл(ПолноеИмя, НовоеИмя);

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

Проверка на существование нужна обязательно. Если файл с новым именем уже есть, вы получите либо исключение, либо, при «тихом» удалении перед переносом, потерю чужих данных. Решите заранее, что правильно для вашей задачи.

Способ 2. Асинхронно в тонком клиенте

Синхронные вызовы на клиенте зависят от свойства конфигурации «Режим использования синхронных вызовов расширений платформы и внешних компонент». В новых конфигурациях их обычно запрещают, поэтому пишите так:

&НаКлиенте
Асинх Процедура СменитьРасширение(Команда)

	НовоеИмя = ИмяСДругимРасширением(ПутьКФайлу, "xml");

	Попытка
		Ждать ПереместитьФайлАсинх(ПутьКФайлу, НовоеИмя);
		ПутьКФайлу = НовоеИмя;
	Исключение
		Сообщить("Не удалось переименовать: " + ОписаниеОшибки());
	КонецПопытки;

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

На платформе ниже 8.3.18 вместо Асинх/Ждать используется НачатьПеремещениеФайла с ОписаниеОповещения.

Способ 3. Копия с новым расширением

Когда исходник трогать нельзя (например, это файл из папки обмена, который заберёт другая программа), используйте КопироватьФайл(Источник, Приемник). Оригинал остаётся, рядом появляется копия с нужным именем.

МетодКогда подходитРиск
ПереместитьФайлсервер, толстый клиент, фоновые заданияпадает, если файл занят
ПереместитьФайлАсинхтонкий и веб-клиент, 8.3.18+нужен Асинх у вызывающей процедуры
КопироватьФайлисходник должен остатьсяна диске два файла, их надо чистить
ДвоичныеДанные.Записатьфайл уже прочитан в памятьрасход памяти на больших файлах

Пакетная смена расширения у файлов в каталоге

Частая задача — поменять .txt на .csv у всех выгрузок в папке. Найти файлы по маске помогает НайтиФайлы:

&НаСервереБезКонтекста
Функция СменитьРасширениеВКаталоге(Каталог, СтароеРасш, НовоеРасш)

	Переименовано = 0;
	Найденные = НайтиФайлы(Каталог, "*." + СтароеРасш, Ложь);

	Для Каждого Файл Из Найденные Цикл

		Если Не Файл.ЭтоФайл() Тогда
			Продолжить;
		КонецЕсли;

		НовоеИмя = ИмяСДругимРасширением(Файл.ПолноеИмя, НовоеРасш);
		Если (Новый Файл(НовоеИмя)).Существует() Тогда
			Продолжить;
		КонецЕсли;

		Попытка
			ПереместитьФайл(Файл.ПолноеИмя, НовоеИмя);
			Переименовано = Переименовано + 1;
		Исключение
			ЗаписьЖурналаРегистрации("СменаРасширения",
				УровеньЖурналаРегистрации.Ошибка, , Файл.ПолноеИмя,
				ОписаниеОшибки());
		КонецПопытки;

	КонецЦикла;

	Возврат Переименовано;

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

Третий параметр Ложь отключает поиск во вложенных папках. Поставьте Истина, если нужен рекурсивный обход.

Массив Найденные формируется один раз до цикла, поэтому переименование внутри цикла его не ломает. Ошибки по отдельным файлам уходят в журнал регистрации, а обработка идёт дальше: один занятый файл не должен останавливать всю пачку.

Маска *.txt в Windows регистронезависима, в Linux — нет. На Linux-сервере ОТЧЕТ.TXT под маску *.txt не попадёт. Если регистр расширений смешанный, ищите по * и сравнивайте НРег(Файл.Расширение).

Настоящая конвертация формата: ДвоичныеДанные, табличный и текстовый документ

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

Табличный документ в Excel, PDF и другие форматы

Отчёт или печатная форма в .mxl превращается в другой формат одной строкой:

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

Среди значений ТипФайлаТабличногоДокумента есть MXL, XLSX, XLS, PDF, HTML, ODS, TXT, DOCX. Полный список для вашей версии платформы смотрите в синтакс-помощнике.

Текстовый файл с другой кодировкой

Если внешняя программа ждёт .csv в Windows-1251, а у вас UTF-8, меняют не только расширение:

Текст = Новый ТекстовыйДокумент;
Текст.Прочитать("C:\Выгрузка\data.txt", КодировкаТекста.UTF8);
Текст.Записать("C:\Выгрузка\data.csv", КодировкаТекста.ANSI);

КодировкаТекста.ANSI — это кодировка системы, на русской Windows обычно 1251. Для точного указания можно передать строкой "windows-1251".

Произвольные файлы через ДвоичныеДанные

ДвоичныеДанные — универсальный контейнер для любого файла. Через него файл переносят между клиентом и сервером, кладут в реквизит типа ХранилищеЗначения, кодируют в Base64:

ДД = Новый ДвоичныеДанные("C:\Входящие\scan");
ДД.Записать("C:\Входящие\scan.pdf");

СтрокаBase64 = Base64Строка(ДД);       // для передачи в JSON или XML
ДДОбратно = Base64Значение(СтрокаBase64);

Проверка: соответствует ли расширение содержимому

Файлы из почты и сканеров часто приходят без расширения или с неверным. Настоящий тип определяют по первым байтам (сигнатуре):

Функция ПервыеБайтыHex(ПолноеИмя, Количество = 4)

	Чтение = Новый ЧтениеДанных(ПолноеИмя);
	Результат = Чтение.Прочитать(Количество);
	Чтение.Закрыть();

	Возврат ВРег(ПолучитьHexСтрокуИзДвоичныхДанных(Результат.ПолучитьДвоичныеДанные()));

КонецФункции
Начало файла (hex)ФорматРасширение
25504446PDF.pdf
504B0304ZIP-контейнер.zip, .xlsx, .docx, .ods
89504E47PNG.png
FFD8FF..JPEG.jpg
D0CF11E0старый формат Office.xls, .doc

Сигнатура 504B0304 общая для архива и офисных файлов нового формата: по ней видно только «это ZIP». Чтобы отличить .xlsx от .docx, откройте файл через ЧтениеZipФайла и посмотрите, есть ли внутри папка xl или word.

Временные файлы и каталоги при смене формата

Конвертацию удобно делать во временном файле, а пользователю отдавать результат. Платформа сама выдаёт уникальное имя с нужным расширением:

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

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

Что здесь важно:

  1. 🧹 Удаляйте временный файл сразу после чтения. Платформа сама его не стирает, и каталог временных файлов сервера за месяцы разрастается до гигабайт.
  2. 📍 ПолучитьИмяВременногоФайла на сервере возвращает путь на сервере, на клиенте — на компьютере пользователя. Каталог берётся из КаталогВременныхФайлов().
  3. 📦 Чтобы отдать файл пользователю, передавайте не путь, а адрес во временном хранилище. На клиенте ПолучитьИзВременногоХранилища(Адрес) вернёт ДвоичныеДанные, а их уже записывают на диск методом Записать.
  4. 🗂️ Для набора файлов создайте временный каталог: ИмяКаталога = ПолучитьИмяВременногоФайла(""), затем СоздатьКаталог(ИмяКаталога). В конце удалите его целиком через УдалитьФайлы(ИмяКаталога).

Не передавайте в УдалитьФайлы путь, собранный из пользовательского ввода, без проверки. Пустая строка или корень диска в переменной каталога — и функция удалит то, что не должна.

Ошибки при переименовании файла и как их обработать

Любую операцию с диском заворачивайте в Попытка ... Исключение. Текст ошибки берите из ОписаниеОшибки(), а для журнала подробнее — ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()).

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

Ещё одна ловушка — недопустимые символы. Если новое имя строится из наименования контрагента или номера документа, в нём могут оказаться /, :, *, ?, ". Windows такой файл не создаст. Заменяйте эти символы на _ до вызова ПереместитьФайл.

Сменить расширение без программирования

Не каждому, кто ищет эту инструкцию, нужен код. Пользователю чаще всего хватает штатного сохранения.

Отчёт или печатная форма в другом формате. Откройте отчёт, нажмите главное меню (кнопка с тремя полосками в заголовке окна) → Файл → Сохранить как.... В диалоге выберите тип файла: Excel, PDF, Word и другие. Программа сама запишет содержимое в выбранном формате. Переименовывать готовый .mxl в проводнике бесполезно.

Внешние обработки и отчёты. Файлы .epf (обработка) и .erf (отчёт) различаются внутренним устройством. Переименование .epf в .erf не превращает обработку в отчёт: такой файл просто не откроется как отчёт.

Файлы конфигурации и выгрузки. .cf, .cfe, .dt — разные форматы со своими командами загрузки в Конфигураторе. Подмена расширения ничего не даст и только запутает того, кто будет загружать файл.

Если в проводнике Windows вы не видите расширения у файлов, включите их показ: в проводнике Вид → Показать → Расширения имён файлов (Windows 11) или галочка «Расширения имён файлов» на вкладке «Вид» (Windows 10). Иначе легко получить отчет.xlsx.mxl вместо задуманного.

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

Почему Файл.Расширение возвращает расширение с точкой?
Так устроено свойство платформы: для data.txt вернётся .txt. Для сравнения используйте НРег(Файл.Расширение) = ".txt", а в ПолучитьИмяВременногоФайла передавайте расширение без точки.
Можно ли поменять расширение у файла, который хранится в информационной базе?
Файл в базе хранится как двоичные данные, а имя и расширение — в реквизитах элемента справочника. Достаточно изменить реквизит с расширением; сами данные переписывать не нужно, если формат не меняется.
Как сменить расширение файла на компьютере пользователя из серверного кода?
Напрямую никак: сервер не видит диск клиента. Отдайте результат через временное хранилище, а запись или переименование выполните в клиентской процедуре.
Работает ли ПереместитьФайл между разными дисками?
Да, функция перемещает файл и между томами. Но на больших файлах это уже копирование с удалением, и оно занимает время. Пока операция идёт, файл в точке назначения может быть недописан.
Чем ПолучитьИмяВременногоФайла лучше своего имени в КаталогВременныхФайлов?
Платформа гарантирует уникальность имени. Два пользователя, которые одновременно формируют отчёт, не перезапишут файлы друг друга.