Полный путь на входе, имя на выходе: разбор строки пути средствами встроенного языка 1С

· 10 мин

Содержание

Чтобы получить имя файла из пути в 1С 8.3, создайте объект Файл и прочитайте его свойство Имя: Новый Файл("C:\Выгрузки\Отчет.xlsx").Имя вернёт Отчет.xlsx. Свойство ИмяБезРасширения даст Отчет, Расширение — .xlsx с точкой, Путь — C:\Выгрузки\ с разделителем на конце. Сам файл при этом может и не существовать: объект разбирает строку, а на диск идёт только при вызове Существует() и подобных методов.

Отдельной глобальной функции «ИмяФайла» во встроенном языке нет. Если объект Файл не подходит (строка пришла с другой ОС, путь собран вручную, код работает в веб-клиенте), имя вырезают функциями работы со строками. Оба способа, работа с расширением, сетевые пути и очистка имени — ниже, с готовым кодом.

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

Объект Файл доступен на клиенте и на сервере. Конструктор принимает строку с полным именем. Всё, что нужно для разбора пути, лежит в его свойствах.

ПолныйПуть = "D:\Обмен\Банк\kl_to_1c.txt";
ФайлОбъект = Новый Файл(ПолныйПуть);

Сообщить(ФайлОбъект.Имя);               // kl_to_1c.txt
Сообщить(ФайлОбъект.ИмяБезРасширения);  // kl_to_1c
Сообщить(ФайлОбъект.Расширение);        // .txt
Сообщить(ФайлОбъект.Путь);              // D:\Обмен\Банк\
Сообщить(ФайлОбъект.ПолноеИмя);         // D:\Обмен\Банк\kl_to_1c.txt

Что вернёт каждое свойство:

СвойствоЧто содержитПример для D:\Обмен\Банк\kl_to_1c.txt
Имяимя с расширениемkl_to_1c.txt
ИмяБезРасширенияимя без последней точки и хвостаkl_to_1c
Расширениерасширение с точкой.txt
Путькаталог с разделителем на концеD:\Обмен\Банк\
ПолноеИмяисходная строка целикомD:\Обмен\Банк\kl_to_1c.txt

Обёртка, которую удобно положить в общий модуль с флажками «Клиент» и «Сервер»:

Функция ИмяФайлаПоПути(Знач ПолныйПуть) Экспорт
    Если ПустаяСтрока(ПолныйПуть) Тогда
        Возврат "";
    КонецЕсли;
    Возврат (Новый Файл(СокрЛП(ПолныйПуть))).Имя;
КонецФункции

СокрЛП здесь не лишний. Пути часто приходят из реквизитов, ячеек Excel или текстовых файлов с пробелом или переводом строки в конце. Без обрезки такой хвост попадёт в имя, и сравнение Имя = "kl_to_1c.txt" не сработает.

Если в конфигурации есть Библиотека стандартных подсистем, посмотрите функцию ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла. Она возвращает структуру с полями ПолноеИмя, Путь, Имя, Расширение, ИмяБезРасширения и работает без объекта Файл. Перед использованием откройте её описание в общем модуле: состав параметров зависит от версии БСП.

Где объект Файл подводит

  • 🐧 Сервер на Linux, путь из Windows. Разделитель на Linux — /. Обратную косую черту объект там не считает разделителем, и Новый Файл("C:\Папка\Счет.pdf").Имя вернёт всю строку целиком.
  • 🌐 Веб-клиент. Объект Файл там есть, но работа с локальной файловой системой ограничена браузером, а полный путь пользователь часто вообще не передаёт.
  • 🔗 URL и пути из внешних систем. Строки вида https://site.ru/files/act.pdf?id=5 объект разберёт по-своему, параметры после ? останутся в имени.

В этих случаях надёжнее ручной разбор строки.

Ручной разбор пути через поиск последнего разделителя

Логика простая: найти последний разделитель каталогов и взять всё, что правее. В платформе 8.3.6 и выше для этого есть СтрНайти с поиском с конца строки.

Функция ИмяФайлаИзСтроки(Знач ПолныйПуть) Экспорт

    Путь = СокрЛП(ПолныйПуть);
    // Приводим оба вида разделителей к одному
    Путь = СтрЗаменить(Путь, "/", "\");

    // Срезаем разделители на конце: "C:\Папка\" -> "C:\Папка"
    Пока СтрЗаканчиваетсяНа(Путь, "\") Цикл
        Путь = Лев(Путь, СтрДлина(Путь) - 1);
    КонецЦикла;

    Позиция = СтрНайти(Путь, "\", НаправлениеПоиска.СКонца);
    Если Позиция = 0 Тогда
        Возврат Путь; // разделителей нет, строка и есть имя
    КонецЕсли;

    Возврат Сред(Путь, Позиция + 1);

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

Прогоним функцию на примерах:

Входная строкаРезультат
C:\Docs\Акт 15.pdfАкт 15.pdf
/home/user1c/exchange/orders.xmlorders.xml
D:\Обмен\Банк\Банк
Прайс.xlsxПрайс.xlsx
пустая строкапустая строка

Строка с разделителем на конце — это путь к каталогу. Функция вернёт имя последней папки. Если вам нужно, чтобы для каталога возвращалась пустая строка, уберите цикл с СтрЗаканчиваетсяНа.

Вариант через СтрРазделить

Короче получается с СтрРазделить. Вторым параметром можно передать сразу несколько символов: каждый из них считается разделителем.

Части = СтрРазделить(СокрЛП(ПолныйПуть), "\/", Ложь);
ИмяФайла = ?(Части.Количество() = 0, "", Части[Части.ВГраница()]);

Третий параметр Ложь выбрасывает пустые элементы. Благодаря ему двойные разделители и косая черта на конце не дают пустого результата. Проверка Количество() = 0 нужна для пустой входной строки, иначе обращение к индексу -1 вызовет ошибку.

Для старых платформ: цикл с Найти

СтрНайти, СтрРазделить и СтрЗаканчиваетсяНа появились в 8.3.6. В конфигурациях, запущенных в режиме совместимости с более ранней версией, этих функций нет. Тогда работает старый приём с Найти, которая ищет только с начала строки:

Путь = СтрЗаменить(СокрЛП(ПолныйПуть), "/", "\");
Позиция = Найти(Путь, "\");
Пока Позиция > 0 Цикл
    Путь = Сред(Путь, Позиция + 1);
    Позиция = Найти(Путь, "\");
КонецЦикла;
ИмяФайла = Путь;

Каждый проход отрезает путь до очередного разделителя. Когда разделителей не осталось, в переменной лежит имя.

Какой способ выбрать

СпособКогда подходитОграничения
Новый Файл(...).Имяпуть локальный, формат совпадает с ОС, где выполняется кодна Linux не понимает \
СтрНайти с концалюбые строки, нужен контроль над разделителямиплатформа 8.3.6+, без режима совместимости
СтрРазделитькороткий код, смешанные разделителиплатформа 8.3.6+
Цикл с Найтистарые конфигурации в режиме совместимостидлиннее, медленнее на очень длинных строках
РазложитьПолноеИмяФайла из БСПв конфигурации есть БСПзависит от версии библиотеки

Имя без расширения и работа с расширением файла

Расширение — всё после последней точки в имени. Ключевое слово здесь «в имени», а не «в пути». Сначала выделите имя, потом ищите точку.

Почему это важно: в пути C:\Отчеты.2025\Выписка точка стоит в имени папки. Если искать её по всей строке, получите «расширение» .2025\Выписка. Объект Файл эту ловушку обходит сам, ручной код — нет.

Функция РазделитьИмяИРасширение(Знач ИмяФайла) Экспорт

    Результат = Новый Структура("ИмяБезРасширения, Расширение", ИмяФайла, "");

    Позиция = СтрНайти(ИмяФайла, ".", НаправлениеПоиска.СКонца);
    // Позиция = 1 — имя начинается с точки, расширения нет
    Если Позиция > 1 Тогда
        Результат.ИмяБезРасширения = Лев(ИмяФайла, Позиция - 1);
        Результат.Расширение = Сред(ИмяФайла, Позиция); // с точкой
    КонецЕсли;

    Возврат Результат;

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

Для Реестр.платежей.xml функция вернёт имя Реестр.платежей и расширение .xml. Для backup.tar.gz расширением считается только .gz. Если нужно распознавать составные расширения, проверяйте их отдельно через СтрЗаканчиваетсяНа.

Проверка типа файла по расширению

Сравнивайте расширение без учёта регистра. Пользователи присылают и .XLSX, и .Xlsx.

Расширение = НРег((Новый Файл(ПолныйПуть)).Расширение);
Если Расширение = ".xlsx" Или Расширение = ".xls" Тогда
    // загрузка из Excel
КонецЕсли;

Замена расширения

Типичная задача — сохранить рядом с исходным файлом его копию в другом формате:

ФайлОбъект = Новый Файл(ПолныйПуть);
НовоеИмя = ФайлОбъект.Путь + ФайлОбъект.ИмяБезРасширения + ".pdf";

Свойство Путь уже содержит разделитель на конце, добавлять его второй раз не нужно.

Сетевые пути UNC и пути на разных ОС

Сетевой путь Windows выглядит так: \\fileserver\obmen\2025\выписка.txt. Два разделителя в начале, затем имя сервера и общая папка. Для извлечения имени файла это обычный путь: последний \ стоит перед выписка.txt, и оба способа выше дают правильный ответ.

Сложности начинаются в другом месте.

  • 🖥️ Код выполняется на сервере 1С. Путь \\fileserver\obmen\... должен быть доступен учётной записи, под которой работает служба сервера 1С, а не пользователю за компьютером. Для разбора строки это неважно, для чтения файла — критично.
  • 🐧 Сервер 1С на Linux. UNC-пути Windows там не работают. Сетевая папка монтируется в каталог вроде /mnt/obmen, и путь в коде нужно строить уже от него.
  • 🔀 Смешанные разделители. Пути, склеенные в коде, нередко выглядят так: \\server\share/folder/file.xml. Перед разбором приведите разделители к одному виду через СтрЗаменить.

Разделитель текущей ОС

Чтобы не зашивать \ или / в код, берите разделитель у платформы:

Разделитель = ПолучитьРазделительПути();

Есть ещё ПолучитьРазделительПутиКлиента() и ПолучитьРазделительПутиСервера(). Они нужны, когда путь формируется на клиенте под Windows, а обрабатывается на сервере под Linux или наоборот.

Путь из диалога выбора файла

Полный путь после ДиалогВыбораФайла лежит в свойстве ПолноеИмяФайла. Имя из него получают тем же объектом Файл прямо на клиенте. В веб-клиенте браузер обычно не отдаёт настоящий путь к файлу на компьютере пользователя: строите логику на имени, а не на каталоге.

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

Как очистить имя файла от недопустимых символов

Обратная задача: имя собирают из данных 1С и сохраняют файл на диск. Например, Акт № 15/3 от 01.10 "Ромашка".pdf. Косая черта и кавычки в Windows запрещены, и ЗаписатьФайл упадёт с ошибкой.

Символы, которые Windows не принимает в имени файла:

СимволГде встречается в данных 1С
\ /номера документов вида 15/3, ИНН/КПП через косую черту
:время в строковых датах, ООО: Ромашка
* ?маски, вопросы в комментариях
"наименования организаций в кавычках
< > |редко, но бывают в комментариях

Кроме того, Windows не принимает имена CON, PRN, AUX, NUL, COM1–COM9, LPT1–LPT9 (с любым расширением) и обрезает точки и пробелы в конце имени.

Функция очистки:

Функция БезопасноеИмяФайла(Знач Имя, Знач Замена = "_") Экспорт

    Недопустимые = "\/:*?""<>|";
    Для Сч = 1 По СтрДлина(Недопустимые) Цикл
        Имя = СтрЗаменить(Имя, Сред(Недопустимые, Сч, 1), Замена);
    КонецЦикла;

    // Табуляции и переводы строк из многострочных реквизитов
    Имя = СтрЗаменить(Имя, Символы.Таб, " ");
    Имя = СтрЗаменить(Имя, Символы.ПС, " ");
    Имя = СтрЗаменить(Имя, Символы.ВК, " ");

    Имя = СокрЛП(Имя);
    // Точки на конце Windows отбросит сама, убираем их явно
    Пока СтрЗаканчиваетсяНа(Имя, ".") Цикл
        Имя = Лев(Имя, СтрДлина(Имя) - 1);
    КонецЦикла;

    Возврат ?(ПустаяСтрока(Имя), "file", Имя);

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

Кавычка внутри строкового литерала во встроенном языке удваивается, поэтому в строке "\/:*?""<>|" она записана как "". Всего в строке девять символов, цикл заменит каждый.

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

ИмяФайла = БезопасноеИмяФайла("Акт № 15/3 ""Ромашка""") + ".pdf";
// Акт № 15_3 _Ромашка_.pdf

В БСП для этой задачи есть ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла. Если библиотека в конфигурации есть, лучше вызывать её, чем держать свою копию.

Длина пути

Классическое ограничение Windows — 260 символов на полный путь. Длинные наименования номенклатуры плюс глубокая структура папок упираются в него быстро. Обрезайте имя через Лев(Имя, 100) до добавления расширения, если оно строится из наименований.

Отладка разбора пути: на что смотреть

Ошибки разбора пути редко ломают программу сразу. Обычно файл сохраняется «не туда» или загрузка молча пропускает строку. Что проверять в отладчике.

  1. Смотрите строку посимвольно. Поставьте точку останова и выведите СтрДлина(Путь). Если длина на 1–2 символа больше видимой, в конце сидит пробел, Символы.ПС или Символы.ВК.
  2. Проверяйте, где выполняется код. Директива &НаСервере у процедуры означает, что разделитель и права определяет сервер. Клиентская машина под Windows и сервер под Linux дают разный результат одной и той же строки кода.
  3. Не путайте имя и существование. Новый Файл(Путь).Имя вернёт имя даже для несуществующего файла. Если дальше файл читается, проверяйте ФайлОбъект.Существует() до чтения.
  4. Логируйте исходную строку. При загрузке из внешних систем запишите сырой путь в журнал регистрации через ЗаписьЖурналаРегистрации. Часто ответ виден сразу по тому, что реально пришло.
  5. Отделяйте параметры URL. Для ссылок вида .../act.pdf?id=5&token=... сначала отрежьте всё после ?, потом выделяйте имя.

Фрагмент для URL:

Позиция = СтрНайти(Адрес, "?");
Если Позиция > 0 Тогда
    Адрес = Лев(Адрес, Позиция - 1);
КонецЕсли;
ИмяФайла = ИмяФайлаИзСтроки(Адрес);

Здесь используется функция ИмяФайлаИзСтроки из раздела про ручной разбор: она уже приводит / к \ и берёт хвост после последнего разделителя.

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

Почему свойство Расширение возвращает значение с точкой?
Так устроен объект Файл: .xlsx, а не xlsx. При сравнении пишите точку в образце или отрежьте её через Сред(Расширение, 2).
Можно ли получить имя файла в запросе 1С?
Язык запросов не умеет искать подстроку с конца. Получите путь запросом, а имя выделите в коде после выборки или храните его в отдельном реквизите.
Как получить имя последней папки в пути?
Срежьте разделитель на конце и примените тот же разбор: для D:\Обмен\Банк\ получится Банк. У объекта Файл для этого подойдёт Новый Файл(СокрЛП(Путь)).Имя для строки без разделителя на конце.
Чем отличаются свойства Имя и ПолноеИмя?
Имя — только имя с расширением. ПолноеИмя — исходная строка с каталогом, то есть то, что вы передали в конструктор.
Нужно ли, чтобы файл существовал, для получения его имени?
Нет. Объект Файл разбирает строку без обращения к диску. Существование проверяет отдельный метод Существует().