Как вытащить имя и расширение файла из строки пути во встроенном языке 1С

· 9 мин

Содержание

Чтобы в 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: не видит.

Имя файла из такого пути вы получите, а открыть сам файл на сервере не сможете. Решения:

  1. Передавайте на сервер не путь, а содержимое: ПоместитьФайлы или НачатьПомещениеФайлов на клиенте, затем ПолучитьИзВременногоХранилища на сервере.
  2. Если файлы читаются с сервера напрямую, указывайте 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-сервере, берите свою функцию с СтрНайти.

Ошибки при разборе пути и как их исправить

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

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

Как получить расширение файла без точки?
Возьмите Сред(ОписаниеФайла.Расширение, 2). Для файла без расширения результат будет пустой строкой, ошибки не возникнет.
Как получить имя папки, в которой лежит файл?
Возьмите свойство Путь объекта Файл, а из него снова выделите последний компонент: (Новый Файл(Лев(Путь, СтрДлина(Путь) - 1))).Имя. Для D:\Обмен\Входящие\акт.pdf получится Входящие.
Создание Новый Файл проверяет, что файл существует?
Нет. Конструктор только разбирает строку. Наличие файла проверяет метод Существует(), а отличить файл от каталога помогают ЭтоФайл() и ЭтоКаталог().
Можно ли получить имя файла в тексте запроса 1С?
Специальных функций для путей в языке запросов нет. Выделяйте имя во встроенном языке после выполнения запроса или храните имя файла в отдельном реквизите.
Как получить имена всех файлов в каталоге?
Используйте НайтиФайлы(Каталог, "*.xml"): функция вернёт массив объектов Файл, у каждого уже есть свойство Имя.