Как вытащить имя и расширение файла из строки пути во встроенном языке 1С
Содержание
Чтобы в 1С получить имя файла из полного пути, создайте объект Новый Файл(ПолныйПуть) и прочитайте его свойство Имя: из строки D:\Обмен\Счет_1045.xlsx вернётся Счет_1045.xlsx. Свойства ИмяБезРасширения, Расширение и Путь дают остальные части пути, а сам файл при этом на диске может и не существовать.
Если объект Файл не подходит (путь пришёл с другой операционной системы, нужен разбор «в лоб» или работа в старом режиме совместимости), имя выделяют поиском последнего разделителя \ или / с конца строки. Ниже оба способа, вариант с регулярным выражением, разбор сетевых и относительных путей и ошибки, на которых чаще всего спотыкаются разработчики. Тема общая для платформы 8.3, от конфигурации не зависит.
Объект Файл: имя файла из полного пути одной строкой
Конструктор Новый Файл() принимает строку и раскладывает её на части. Обращения к диску в этот момент не происходит: свойства считаются по тексту пути.
ПолныйПуть = "D:\Обмен\Входящие\Счет_1045.xlsx";
ОписаниеФайла = Новый Файл(ПолныйПуть);
ИмяФайла = ОписаниеФайла.Имя; // "Счет_1045.xlsx"
ИмяБезРасширения = ОписаниеФайла.ИмяБезРасширения; // "Счет_1045"
Расширение = ОписаниеФайла.Расширение; // ".xlsx" — с точкой
Каталог = ОписаниеФайла.Путь; // "D:\Обмен\Входящие\"
Что возвращает каждое свойство:
| Свойство | Пример результата | Комментарий |
|---|---|---|
Имя | Счет_1045.xlsx | имя вместе с расширением |
ИмяБезРасширения | Счет_1045 | всё до последней точки |
Расширение | .xlsx | с ведущей точкой; у файла без расширения — пустая строка |
Путь | D:\Обмен\Входящие\ | каталог с завершающим разделителем |
ПолноеИмя | D:\Обмен\Входящие\Счет_1045.xlsx | исходный путь целиком |
Для имени вида archive.tar.gz расширением считается только последняя часть: Расширение вернёт .gz, а ИмяБезРасширения — archive.tar. Если нужно отрезать оба суффикса, делайте это отдельно по своему правилу.
Проверка на Неопределено и пустую строку
Путь часто приходит из реквизита формы, параметра процедуры или результата диалога. Если пользователь закрыл диалог, в переменной окажется Неопределено или пустая строка. Перед созданием объекта Файл поставьте защиту:
Если ТипЗнч(ПолныйПуть) <> Тип("Строка") Или ПустаяСтрока(ПолныйПуть) Тогда
ИмяФайла = "";
Иначе
ИмяФайла = (Новый Файл(СокрЛП(ПолныйПуть))).Имя;
КонецЕсли;
Нужно узнать, есть ли такой файл на самом деле, — вызовите ОписаниеФайла.Существует(). Это уже обращение к диску, поэтому проверку делайте на той стороне (клиент или сервер), где файл реально лежит.
Получение имени файла поиском последнего разделителя
Ручной разбор нужен, когда хочется полностью контролировать результат: путь мог прийти с Linux-сервера, из URL или из стороннего XML. Идея простая: найти последний \ или / и взять всё, что правее.
Вариант для платформы 8.3.6 и выше: СтрНайти с конца
Функция СтрНайти умеет искать с конца строки, если передать НаправлениеПоиска.СКонца. Она возвращает позицию символа (счёт с 1) или 0, если символ не найден.
Функция ИмяФайлаИзПути(Знач ПолныйПуть) Экспорт
Если ТипЗнч(ПолныйПуть) <> Тип("Строка") Тогда
Возврат "";
КонецЕсли;
// Приводим оба вида разделителей к одному
Путь = СтрЗаменить(СокрЛП(ПолныйПуть), "/", "\");
// Убираем завершающие разделители: "C:\Temp\" -> "C:\Temp"
Пока СтрЗаканчиваетсяНа(Путь, "\") Цикл
Путь = Лев(Путь, СтрДлина(Путь) - 1);
КонецЦикла;
Позиция = СтрНайти(Путь, "\", НаправлениеПоиска.СКонца);
Если Позиция = 0 Тогда
Возврат Путь; // разделителей нет — строка уже является именем
КонецЕсли;
Возврат Сред(Путь, Позиция + 1);
КонецФункции
Проверка на примерах:
- 📄
D:\Обмен\акт.pdf→акт.pdf; - 🐧
/home/usr1cv8/exchange/акт.pdf→акт.pdf; - 📁
C:\Temp\→Temp(последний компонент пути); - ✏️
акт.pdf→акт.pdf.
Функцию удобно положить в общий модуль с флажками «Клиент» и «Сервер», тогда она будет доступна с обеих сторон.
Вариант через СтрРазделить
Короче, но создаёт массив из всех частей пути. Третий параметр Ложь отбрасывает пустые элементы, поэтому завершающий слеш не мешает.
Части = СтрРазделить(СтрЗаменить(ПолныйПуть, "/", "\"), "\", Ложь);
ИмяФайла = ?(Части.Количество() = 0, "", Части[Части.Количество() - 1]);
Имя без расширения тем же приёмом
Когда имя уже выделено, расширение отрезают по последней точке. Точку в начале имени (.gitignore) не считайте началом расширения, иначе имя станет пустым.
ПозицияТочки = СтрНайти(ИмяФайла, ".", НаправлениеПоиска.СКонца);
Если ПозицияТочки > 1 Тогда
ИмяБезРасширения = Лев(ИмяФайла, ПозицияТочки - 1);
Расширение = Сред(ИмяФайла, ПозицияТочки + 1); // "xlsx", без точки
Иначе
ИмяБезРасширения = ИмяФайла;
Расширение = "";
КонецЕсли;
Для Счет_1045.xlsx точка стоит на позиции 10: Лев(..., 9) даёт Счет_1045, Сред(..., 11) даёт xlsx.
Вариант для старого режима совместимости
Если конфигурация работает в режиме совместимости ниже 8.3.6, функций СтрНайти, СтрРазделить и СтрЗаканчиваетсяНа в ней нет. Тогда идите по строке с конца циклом:
Функция ИмяФайлаИзПутиБезСтрНайти(ПолныйПуть)
Длина = СтрДлина(ПолныйПуть);
Для Сч = 0 По Длина - 1 Цикл
Позиция = Длина - Сч;
Символ = Сред(ПолныйПуть, Позиция, 1);
Если Символ = "\" Или Символ = "/" Тогда
Возврат Сред(ПолныйПуть, Позиция + 1);
КонецЕсли;
КонецЦикла;
Возврат ПолныйПуть;
КонецФункции
Для строки a\bcd цикл дойдёт до позиции 2, где стоит \, и вернёт Сред(..., 3), то есть bcd. Для пустой строки цикл не выполнится ни разу, функция вернёт пустую строку.
Как выделить имя файла регулярным выражением
Регулярка удобна, когда путь нужно не только разобрать, но и проверить: например, принять только файлы .xml или имена по маске Счет_<номер>.
Шаблон для имени файла: [^\\/]+$. Он означает «один или больше символов, среди которых нет \ и /, вплотную к концу строки».
Через COM-объект VBScript.RegExp (Windows)
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.Pattern = "[^\\/]+$";
RegExp.Global = Ложь;
Совпадения = RegExp.Execute(ПолныйПуть);
Если Совпадения.Count > 0 Тогда
ИмяФайла = Совпадения.Item(0).Value;
Иначе
ИмяФайла = "";
КонецЕсли;
В строках 1С обратная косая черта не экранируется, поэтому "[^\\/]+$" попадает в движок регулярных выражений именно в таком виде.
Ограничения способа:
- 🪟 работает только на Windows: на сервере под Linux и в веб-клиенте COM недоступен;
- ⏳ создание COM-объекта медленнее строковых функций, в цикле по тысячам файлов разница заметна;
- 📦 компонент VBScript Microsoft переводит в разряд устаревших, в будущих сборках Windows его может не оказаться по умолчанию.
Встроенные функции регулярных выражений
В новых версиях платформы 8.3 появились собственные функции для регулярных выражений: СтрСоответствуетШаблону, СтрНайтиПоРегулярномуВыражению, СтрЗаменитьПоРегулярномуВыражению и другие. Если они есть в синтакс-помощнике вашей платформы, имя можно получить без COM: удалить всё до последнего разделителя.
ИмяФайла = СтрЗаменитьПоРегулярномуВыражению(ПолныйПуть, "^.*[\\/]", "");
Жадное .* захватывает максимум символов, поэтому удаляется всё до последнего слеша включительно. Такой код работает и на Linux-сервере.
Имя файла из сетевого пути и UNC-адреса
Сетевой путь вида \\srv-files\Обмен\Входящие\акт.pdf разбирается так же, как локальный. Объект Файл вернёт акт.pdf, функция поиска с конца — тоже.
Особые случаи, которые стоит учесть:
- 🖧 Путь до общей папки без файла. Для
\\srv-files\Обменпоследним компонентом будет имя ресурсаОбмен. Если ожидается файл, проверьте расширение или вызовитеСуществует()иЭтоФайл(). - 🔤 Длинные пути с префиксом
\\?\. Префикс не мешает поиску последнего разделителя, имя выделится корректно. - 🌐 Адрес в виде URL. В
https://site.ru/files/прайс.xlsx?v=3после последнего/стоитпрайс.xlsx?v=3. Сначала отрежьте всё после?и#, потом выделяйте имя. Кириллица в URL может прийти закодированной (%D0%BF...), её раскодируют функциейРаскодироватьСтрокусо способомСпособКодированияСтроки.КодировкаURL.
Сетевой диск и служба сервера 1С
На практике путь часто ломается не при разборе, а при чтении файла. Пользователь выбирает файл на подключённом диске Z:\Обмен\акт.pdf, путь уходит на сервер, а там служба 1С работает под своей учётной записью (по умолчанию USR1CV8) и диска Z: не видит.
Имя файла из такого пути вы получите, а открыть сам файл на сервере не сможете. Решения:
- Передавайте на сервер не путь, а содержимое:
ПоместитьФайлыилиНачатьПомещениеФайловна клиенте, затемПолучитьИзВременногоХранилищана сервере. - Если файлы читаются с сервера напрямую, указывайте UNC-путь (
\\srv-files\Обмен\...) и выдайте учётной записи службы права на эту папку.
Относительные пути и текущий каталог
Строка ..\Шаблоны\бланк.docx или .\выгрузка.xml — относительный путь. Свойство Имя и функции поиска разделителя дают из неё правильное имя (бланк.docx, выгрузка.xml): им всё равно, абсолютный путь или нет.
Проблема в другом: относительно какого каталога этот путь считать. У клиентского приложения текущий каталог зависит от ярлыка запуска, у процесса сервера — от настроек службы. Поэтому:
- 🚫 не полагайтесь на
ПолноеИмяотносительного пути как на реальное местоположение файла; - ✅ собирайте абсолютный путь сами из известного каталога и имени файла.
Какие каталоги можно получить программно:
| Функция | Что возвращает |
|---|---|
КаталогВременныхФайлов() | каталог временных файлов текущего пользователя ОС |
ПолучитьИмяВременногоФайла("xml") | полный путь к новому временному файлу с заданным расширением |
КаталогПрограммы() | каталог исполняемых файлов платформы (bin) |
Пример: сохранить файл с исходным именем во временный каталог.
ИмяФайла = (Новый Файл(ПолныйПуть)).Имя;
ПутьКопии = КаталогВременныхФайлов() + ИмяФайла;
КаталогВременныхФайлов() обычно возвращает путь с завершающим разделителем, но не стоит закладываться на это вслепую. Надёжнее проверить последний символ через СтрЗаканчиваетсяНа и добавить ПолучитьРазделительПути(), если его нет. Функция ПолучитьРазделительПути() вернёт \ на Windows и / на Linux.
Веб-клиент: полного пути нет
В веб-клиенте браузер не передаёт приложению реальный путь к файлу на компьютере пользователя. После помещения файла вы получите только имя, иногда с подставным каталогом вроде C:\fakepath\. Поэтому в веб-клиенте функцию выделения имени применяйте всё равно: она уберёт мусорный префикс и оставит акт.pdf.
Какой способ получения имени файла выбрать
| Способ | Где работает | Плюсы | Минусы |
|---|---|---|---|
Новый Файл(...).Имя | клиент и сервер | одна строка, сразу есть имя, расширение, каталог | разделители трактуются по правилам ОС той стороны, где выполняется код |
СтрНайти с конца + Сред | клиент и сервер, 8.3.6+ | полный контроль, понимает оба слеша | нужно написать функцию |
СтрРазделить | клиент и сервер, 8.3.6+ | коротко | создаёт лишний массив |
| Цикл по символам | любая версия | работает в старом режиме совместимости | медленнее и длиннее |
VBScript.RegExp | только Windows | проверка формата имени вместе с разбором | COM, нет на Linux и в веб-клиенте |
Для повседневных задач хватает объекта Файл. Если код должен одинаково работать на Windows-клиенте и Linux-сервере, берите свою функцию с СтрНайти.
Ошибки при разборе пути и как их исправить
\ не разделитель, и объект Файл может принять всю строку за имя. Замените \ на / перед разбором или используйте функцию с поиском обоих разделителей.Сред передана позиция разделителя без + 1. Правильно: Сред(Путь, Позиция + 1).Найти или СтрНайти без направления поиска: она находит первый разделитель. Для последнего нужен НаправлениеПоиска.СКонца.C:\Temp\) или в строку попали пробелы и перевод строки. Удалите завершающие слеши и примените СокрЛП до разбора.Расширение сохраняет регистр исходного имени. Сравнивайте через НРег(ОписаниеФайла.Расширение) = ".xlsx".Частые вопросы
Как получить расширение файла без точки?
Сред(ОписаниеФайла.Расширение, 2). Для файла без расширения результат будет пустой строкой, ошибки не возникнет.Как получить имя папки, в которой лежит файл?
Путь объекта Файл, а из него снова выделите последний компонент: (Новый Файл(Лев(Путь, СтрДлина(Путь) - 1))).Имя. Для D:\Обмен\Входящие\акт.pdf получится Входящие.Создание Новый Файл проверяет, что файл существует?
Существует(), а отличить файл от каталога помогают ЭтоФайл() и ЭтоКаталог().Можно ли получить имя файла в тексте запроса 1С?
Как получить имена всех файлов в каталоге?
НайтиФайлы(Каталог, "*.xml"): функция вернёт массив объектов Файл, у каждого уже есть свойство Имя.