Смена расширения и формата файла кодом 1С:Предприятия 8.3
Содержание
Чтобы изменить расширение файла в 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) | Формат | Расширение |
|---|---|---|
25504446 | .pdf | |
504B0304 | ZIP-контейнер | .zip, .xlsx, .docx, .ods |
89504E47 | PNG | .png |
FFD8FF.. | JPEG | .jpg |
D0CF11E0 | старый формат Office | .xls, .doc |
Сигнатура 504B0304 общая для архива и офисных файлов нового формата: по ней видно только «это ZIP». Чтобы отличить .xlsx от .docx, откройте файл через ЧтениеZipФайла и посмотрите, есть ли внутри папка xl или word.
Временные файлы и каталоги при смене формата
Конвертацию удобно делать во временном файле, а пользователю отдавать результат. Платформа сама выдаёт уникальное имя с нужным расширением:
ИмяВрем = ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ИмяВрем, ТипФайлаТабличногоДокумента.XLSX);
ДД = Новый ДвоичныеДанные(ИмяВрем);
УдалитьФайлы(ИмяВрем);
Возврат ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификаторФормы);
Что здесь важно:
- 🧹 Удаляйте временный файл сразу после чтения. Платформа сама его не стирает, и каталог временных файлов сервера за месяцы разрастается до гигабайт.
- 📍
ПолучитьИмяВременногоФайлана сервере возвращает путь на сервере, на клиенте — на компьютере пользователя. Каталог берётся изКаталогВременныхФайлов(). - 📦 Чтобы отдать файл пользователю, передавайте не путь, а адрес во временном хранилище. На клиенте
ПолучитьИзВременногоХранилища(Адрес)вернётДвоичныеДанные, а их уже записывают на диск методомЗаписать. - 🗂️ Для набора файлов создайте временный каталог:
ИмяКаталога = ПолучитьИмяВременногоФайла(""), затемСоздатьКаталог(ИмяКаталога). В конце удалите его целиком черезУдалитьФайлы(ИмяКаталога).
Не передавайте в УдалитьФайлы путь, собранный из пользовательского ввода, без проверки. Пустая строка или корень диска в переменной каталога — и функция удалит то, что не должна.
Ошибки при переименовании файла и как их обработать
Любую операцию с диском заворачивайте в Попытка ... Исключение. Текст ошибки берите из ОписаниеОшибки(), а для журнала подробнее — ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()).
Ещё одна ловушка — недопустимые символы. Если новое имя строится из наименования контрагента или номера документа, в нём могут оказаться /, :, *, ?, ". Windows такой файл не создаст. Заменяйте эти символы на _ до вызова ПереместитьФайл.
Сменить расширение без программирования
Не каждому, кто ищет эту инструкцию, нужен код. Пользователю чаще всего хватает штатного сохранения.
Отчёт или печатная форма в другом формате. Откройте отчёт, нажмите главное меню (кнопка с тремя полосками в заголовке окна) → Файл → Сохранить как.... В диалоге выберите тип файла: Excel, PDF, Word и другие. Программа сама запишет содержимое в выбранном формате. Переименовывать готовый .mxl в проводнике бесполезно.
Внешние обработки и отчёты. Файлы .epf (обработка) и .erf (отчёт) различаются внутренним устройством. Переименование .epf в .erf не превращает обработку в отчёт: такой файл просто не откроется как отчёт.
Файлы конфигурации и выгрузки. .cf, .cfe, .dt — разные форматы со своими командами загрузки в Конфигураторе. Подмена расширения ничего не даст и только запутает того, кто будет загружать файл.
Если в проводнике Windows вы не видите расширения у файлов, включите их показ: в проводнике Вид → Показать → Расширения имён файлов (Windows 11) или галочка «Расширения имён файлов» на вкладке «Вид» (Windows 10). Иначе легко получить отчет.xlsx.mxl вместо задуманного.
Частые вопросы
Почему Файл.Расширение возвращает расширение с точкой?
data.txt вернётся .txt. Для сравнения используйте НРег(Файл.Расширение) = ".txt", а в ПолучитьИмяВременногоФайла передавайте расширение без точки.