Файл 1С программно: создать, прочитать, удалить

Дата: 21.09.2026 10:02:05
Файлы 1С
Обработки
Интеграции
Программирование 1С
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Управляемые

Создать, прочитать, скопировать или удалить файл 1С программно можно за несколько строк: объект Файл и методы глобального контекста покрывают почти все задачи. Ошибки возникают в другом месте — клиентский и серверный код видят разные диски. Ниже законченные примеры для платформы 8.3: проверка и поиск файлов, архив, текст в UTF-8 и Windows-1251, временные файлы, ZIP и передача файла между клиентом и сервером.

Где выполняется код и чей диск он видит

КодЧей дискЧто учесть
Серверный в клиент-серверной базе: &НаСервере, общие модули, фоновые и регламентные заданияСервера 1СПрава учётной записи службы (по умолчанию USR1CV8), сетевые папки — только по UNC-пути
Серверный в файловой базеКомпьютера, где запущен клиент; для веб-клиента — веб-сервераКод с локальными путями работает здесь и ломается после перехода на сервер
&НаКлиенте в тонком клиентеПользователяСинхронные методы — только если их разрешают свойства конфигурации, иначе методы …Асинх
&НаКлиенте в веб-клиентеПользователя, через расширение для работы с файламиБез расширения — только диалог выбора и временное хранилище

Главное правило: серверу передают не путь, а содержимое файла через временное хранилище. Путь C:\Users\Иван\Desktop\прайс.csv на сервере указывает на диск сервера. Примеры ниже, кроме клиентских процедур, работают с диском сервера 1С.

Объект Файл: существует ли файл, размер и дата изменения

Один и тот же путь проверяем на сервере и на клиенте — в клиент-серверной базе ответы будут разными.

// Модуль формы обработки: реквизит ПутьКФайлу (Строка), команда ПроверитьФайл.

&НаКлиенте
Асинх Процедура ПроверитьФайл(Команда)

    // 1. Путь на диске сервера 1С
    НаСервере = СведенияОФайлеНаСервере(ПутьКФайлу);
    Если НаСервере.Существует Тогда
        Сообщить(СтрШаблон("Сервер: %1, %2 байт, изменён %3", НаСервере.Имя,
            Формат(НаСервере.Размер, "ЧГ=0; ЧН=0"), НаСервере.Изменен));
    Иначе
        Сообщить("Сервер: файл не найден");
    КонецЕсли;

    // 2. Тот же путь на компьютере пользователя
    Если Не Ждать ПодключитьРасширениеРаботыСФайламиАсинх() Тогда
        Сообщить("Клиент: в веб-клиенте нужно расширение для работы с файлами");
        Возврат;
    КонецЕсли;
    Файл = Новый Файл(ПутьКФайлу);
    Если Ждать Файл.СуществуетАсинх() Тогда
        Размер = Ждать Файл.РазмерАсинх();
        Сообщить(СтрШаблон("Клиент: %1, %2 байт", Файл.Имя, Формат(Размер, "ЧГ=0; ЧН=0")));
    Иначе
        Сообщить("Клиент: файл не найден");
    КонецЕсли;

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

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

    Сведения = Новый Структура("Имя, Существует, ЭтоКаталог, Размер, Изменен",
        "", Ложь, Ложь, 0, Дата(1, 1, 1));
    Файл = Новый Файл(ПолноеИмя);
    Сведения.Имя = Файл.Имя; // свойство: разбор строки, к диску не обращается
    Если Не Файл.Существует() Тогда
        Возврат Сведения;
    КонецЕсли;

    Сведения.Существует = Истина;
    Сведения.ЭтоКаталог = Файл.ЭтоКаталог();
    Сведения.Изменен = Файл.ПолучитьВремяИзменения();
    Если Не Сведения.ЭтоКаталог Тогда
        Сведения.Размер = Файл.Размер(); // в байтах
    КонецЕсли;
    Возврат Сведения;

КонецФункции
  • Свойства Имя, ИмяБезРасширения, Расширение (с точкой: .xml) и Путь разбирают строку и к диску не обращаются. Методы Существует(), ЭтоКаталог(), Размер(), ПолучитьВремяИзменения() читают файловую систему, поэтому на клиенте у них есть пары СуществуетАсинх(), ЭтоКаталогАсинх(), РазмерАсинх().
  • ПолучитьВремяИзменения() возвращает местное время компьютера, где выполняется код. Для сравнения с текущим моментом удобнее ПолучитьУниверсальноеВремяИзменения() и ТекущаяУниверсальнаяДата().
  • ПодключитьРасширениеРаботыСФайламиАсинх() в тонком клиенте возвращает Истина, в веб-клиенте без установленного расширения — Ложь.

НайтиФайлы: поиск по маске, перенос в архив, удаление

Типовая задача обмена: забрать XML из каталога и подкаталогов, переложить в архив по датам, старые дни удалить. Модуль ФайлыСервер — без флажка «Вызов сервера»: перемещать и удалять файлы клиент напрямую не должен.

// Общий модуль ФайлыСервер: флажок «Сервер», без «Вызов сервера».

// Переносит XML из каталога обмена и его подкаталогов в архив за текущий день.
// Возвращает массив полных имён файлов в архиве.
Функция ПеренестиВАрхив(КаталогВходящих, КаталогАрхива) Экспорт

    КаталогДня = СРазделителем(КаталогАрхива) + Формат(ТекущаяДатаСеанса(), "ДФ=yyyy-MM-dd");
    ОбъектКаталога = Новый Файл(КаталогДня);
    Если Не ОбъектКаталога.Существует() Тогда
        СоздатьКаталог(КаталогДня);
    КонецЕсли;
    КаталогДня = СРазделителем(КаталогДня);

    Перенесенные = Новый Массив;
    Для Каждого Файл Из НайтиФайлы(КаталогВходящих, "*.xml", Истина) Цикл

        Если Файл.ЭтоКаталог() Тогда
            Продолжить; // маске соответствуют и каталоги
        КонецЕсли;
        Если ТекущаяУниверсальнаяДата() - Файл.ПолучитьУниверсальноеВремяИзменения() < 60 Тогда
            Продолжить; // файл моложе минуты: отправитель мог его ещё не дописать
        КонецЕсли;

        Приемник = КаталогДня + Файл.Имя;
        ФайлПриемника = Новый Файл(Приемник);
        Если ФайлПриемника.Существует() Тогда
            Приемник = КаталогДня + Файл.ИмяБезРасширения + "_"
                + Лев(Строка(Новый УникальныйИдентификатор), 8) + Файл.Расширение;
        КонецЕсли;

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

    КонецЦикла;

    Возврат Перенесенные;

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

// Удаляет из архива каталоги дней, которые не менялись дольше КоличествоДней.
Процедура ОчиститьАрхив(КаталогАрхива, КоличествоДней = 30) Экспорт

    Граница = ТекущаяУниверсальнаяДата() - КоличествоДней * 86400;
    Для Каждого Каталог Из НайтиФайлы(КаталогАрхива, ПолучитьМаскуВсеФайлы(), Ложь) Цикл
        Если Не Каталог.ЭтоКаталог() Или Каталог.ПолучитьУниверсальноеВремяИзменения() >= Граница Тогда
            Продолжить;
        КонецЕсли;
        Попытка
            УдалитьФайлы(Каталог.ПолноеИмя); // каталог удаляется вместе с содержимым
        Исключение
            ЗаписьЖурналаРегистрации("Обмен.Архив", УровеньЖурналаРегистрации.Предупреждение, , ,
                Каталог.ПолноеИмя + Символы.ПС + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
        КонецПопытки;
    КонецЦикла;

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

Функция СРазделителем(Путь)

    Разделитель = ПолучитьРазделительПути();
    Возврат ?(СтрЗаканчиваетсяНа(Путь, Разделитель), Путь, Путь + Разделитель);

КонецФункции
  • НайтиФайлы(Каталог, "*.xml", Истина) возвращает массив объектов Файл из каталога и всех подкаталогов. Маска одна: для XML и JSON нужны два вызова либо ПолучитьМаскуВсеФайлы() и проверка Расширение.
  • Маска *.* на Linux не находит файлы без точки в имени, а имена там чувствительны к регистру: заказ.XML и заказ.xml — разные файлы. ПолучитьМаскуВсеФайлы() и ПолучитьРазделительПути() возвращают значения для ОС, где выполняется код.
  • Архив держите вне каталога входящих, иначе рекурсивный поиск найдёт уже перенесённые файлы.
  • ПереместитьФайл обёрнут в Попытка: занятый файл не останавливает остальные, причина уходит в журнал. При совпадении имени в архиве к нему добавляется уникальный суффикс. Для копии вместо переноса — КопироватьФайл с теми же параметрами.
  • УдалитьФайлы(ПолноеИмяКаталога) удаляет каталог с содержимым, УдалитьФайлы(Каталог, "*.tmp") — файлы по маске, сам каталог остаётся. Корзины нет: удалённое не восстановить.

Создать файл 1С программно: ЗаписьТекста и ЧтениеТекста с кодировкой

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

// Общий модуль ФайлыСервер.

// Выгружает прайс в CSV для программы, которая ждёт Windows-1251, «;» и перевод строки CRLF.
// Товары — таблица значений с колонками Артикул, Наименование, Цена.
Процедура ВыгрузитьПрайсCSV(ИмяФайла, Товары) Экспорт

    Запись = Новый ЗаписьТекста(ИмяФайла, "windows-1251", , , Символы.ВК + Символы.ПС);
    Попытка
        Запись.ЗаписатьСтроку("Артикул;Наименование;Цена");
        Для Каждого Товар Из Товары Цикл
            Запись.ЗаписатьСтроку(СтрШаблон("%1;%2;%3",
                Товар.Артикул,
                СтрЗаменить(Товар.Наименование, ";", ","),
                Формат(Товар.Цена, "ЧДЦ=2; ЧН=0; ЧГ=0")));
        КонецЦикла;
        Запись.Закрыть();
    Исключение
        Запись.Закрыть();
        ВызватьИсключение;
    КонецПопытки;

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

// Читает текстовый файл построчно и возвращает непустые строки.
Функция ПрочитатьСтроки(ИмяФайла, Кодировка = "UTF-8") Экспорт

    Строки = Новый Массив;
    Чтение = Новый ЧтениеТекста(ИмяФайла, Кодировка);
    Попытка
        СтрокаФайла = Чтение.ПрочитатьСтроку();
        Пока СтрокаФайла <> Неопределено Цикл
            Если Не ПустаяСтрока(СтрокаФайла) Тогда
                Строки.Добавить(СтрокаФайла);
            КонецЕсли;
            СтрокаФайла = Чтение.ПрочитатьСтроку();
        КонецЦикла;
        Чтение.Закрыть();
    Исключение
        Чтение.Закрыть();
        ВызватьИсключение;
    КонецПопытки;

    Возврат Строки;

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

// Перекодирует файл, например из "windows-1251" в "UTF-8".
// Исходник остаётся рядом с расширением .bak.
Процедура ПерекодироватьФайл(ИмяФайла, ИзКодировки, ВКодировку, ЗаписатьBOM = Ложь) Экспорт

    Копия = Новый Файл(ИмяФайла + ".bak");
    Если Копия.Существует() Тогда
        УдалитьФайлы(Копия.ПолноеИмя);
    КонецЕсли;
    КопироватьФайл(ИмяФайла, Копия.ПолноеИмя);

    Текст = ПолучитьСтрокуИзДвоичныхДанных(Новый ДвоичныеДанные(ИмяФайла), ИзКодировки);
    ПолучитьДвоичныеДанныеИзСтроки(Текст, ВКодировку, ЗаписатьBOM).Записать(ИмяФайла);

КонецПроцедуры
  • Строка "windows-1251" надёжнее КодировкаТекста.ANSI: ANSI — кодовая страница операционной системы, и на Linux-сервере это может быть не 1251.
  • Пятый параметр ЗаписьТекста — перевод строки в файле. Явный CRLF нужен Windows-программам, а выгрузку может выполнять и Linux-сервер.
  • Закрыть() стоит в обеих ветках: пока объект не закрыт, файл занят и конец данных может не попасть на диск. ПрочитатьСтроку() возвращает Неопределено в конце файла — это условие выхода из цикла.
  • ЗаписьТекста с КодировкаТекста.UTF8 пишет в начало файла BOM — байты EF BB BF. Часть внешних API и парсеров на нём спотыкается, поэтому ПерекодироватьФайл пишет через ПолучитьДвоичныеДанныеИзСтроки: третий параметр решает, будет ли BOM. Подробнее о строках и байтах — в статье о двоичных данных.
  • КопироватьФайл оставляет страховочную копию; старую копию удаляем заранее.

Файлы создают и другие объекты — ТабличныйДокумент.Записать, ЗаписьXML.ОткрытьФайл, ЗаписьJSON.ОткрытьФайл, ДвоичныеДанные.Записать, — правила про клиент и сервер для них те же. Сохранение в XLSX разобрано в руководстве по табличному документу, хранение файла-шаблона в конфигурации — в статье о макетах.

Временные файлы и упаковка в ZIP

Архиватору нужны файлы на диске, поэтому содержимое сначала пишется во временный каталог.

// Общий модуль ФайлыСервер.

// Упаковывает файлы в ZIP и возвращает архив как ДвоичныеДанные.
// Файлы — соответствие: ключ — имя файла в архиве без каталогов,
// значение — ДвоичныеДанные или Строка (запишется в UTF-8 без BOM).
Функция УпаковатьВZip(Файлы) Экспорт

    КаталогФайлов = КаталогВременныхФайлов() + "zip_" + Строка(Новый УникальныйИдентификатор)
        + ПолучитьРазделительПути();
    ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
    СоздатьКаталог(КаталогФайлов);

    Попытка
        Архив = Новый ЗаписьZipФайла(ИмяАрхива, , , , УровеньСжатияZIP.Максимальный);
        Для Каждого КлючИЗначение Из Файлы Цикл
            Данные = КлючИЗначение.Значение;
            Если ТипЗнч(Данные) = Тип("Строка") Тогда
                Данные = ПолучитьДвоичныеДанныеИзСтроки(Данные, "UTF-8", Ложь);
            КонецЕсли;
            ПолноеИмя = КаталогФайлов + КлючИЗначение.Ключ;
            Данные.Записать(ПолноеИмя);
            Архив.Добавить(ПолноеИмя, РежимСохраненияПутейZIP.НеСохранятьПути);
        КонецЦикла;
        Архив.Записать();
        Результат = Новый ДвоичныеДанные(ИмяАрхива);
    Исключение
        УдалитьВременное(КаталогФайлов);
        УдалитьВременное(ИмяАрхива);
        ВызватьИсключение;
    КонецПопытки;

    УдалитьВременное(КаталогФайлов);
    УдалитьВременное(ИмяАрхива);
    Возврат Результат;

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

// Удаляет временный файл или каталог. Ошибку не пробрасывает, а пишет в журнал:
// неудачная уборка не должна отменять готовый результат.
Процедура УдалитьВременное(Путь)

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

КонецПроцедуры
  • КаталогВременныхФайлов() возвращает путь с разделителем на конце. Каталог общий для всех сеансов рабочего процесса, поэтому подкаталог получает уникальное имя.
  • ПолучитьИмяВременногоФайла("zip") только придумывает уникальное имя в этом каталоге и файл не создаёт. Платформа временные файлы за вас не удаляет, а блока «finally» в языке нет — уборка повторена в ветке Исключение перед ВызватьИсключение.
  • Временный файл живёт в пределах одного серверного вызова. В кластере с несколькими рабочими серверами следующий вызов может выполниться на другом компьютере, где файла нет. Между вызовами передавайте ДвоичныеДанные через временное хранилище.
  • Каталог целиком добавляется одной строкой: Архив.Добавить(Каталог + ПолучитьМаскуВсеФайлы(), РежимСохраненияПутейZIP.СохранятьОтносительныеПути, РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно).

Распаковка ZIP: ЧтениеZipФайла с проверками

Архив от пользователя или контрагента — недоверенные данные: сначала проверяем объём, потом извлекаем только нужные файлы.

// Общий модуль ФайлыСервер. УдалитьВременное — из предыдущего листинга.

// Извлекает из ZIP файлы с нужным расширением.
// Возвращает соответствие: путь внутри архива — ДвоичныеДанные файла.
Функция РаспаковатьZip(ДанныеАрхива, Расширение = ".xml", ЛимитБайт = 104857600) Экспорт

    ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
    КаталогРаспаковки = ПолучитьИмяВременногоФайла() + ПолучитьРазделительПути();
    ДанныеАрхива.Записать(ИмяАрхива);
    СоздатьКаталог(КаталогРаспаковки);

    Результат = Новый Соответствие;
    Архив = Неопределено;
    Попытка
        Архив = Новый ЧтениеZipФайла(ИмяАрхива);

        Всего = 0;
        Для Каждого Элемент Из Архив.Элементы Цикл
            Всего = Всего + Элемент.НесжатыйРазмер;
        КонецЦикла;
        Если Всего > ЛимитБайт Тогда
            ВызватьИсключение СтрШаблон("Архив распаковывается в %1 байт, допустимо %2",
                Формат(Всего, "ЧГ=0"), Формат(ЛимитБайт, "ЧГ=0"));
        КонецЕсли;

        Для Каждого Элемент Из Архив.Элементы Цикл
            Если Не СтрЗаканчиваетсяНа(НРег(Элемент.Имя), НРег(Расширение)) Тогда
                Продолжить; // каталоги и файлы других типов
            КонецЕсли;
            Архив.Извлечь(Элемент, КаталогРаспаковки, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
            ПутьКФайлу = КаталогРаспаковки + Элемент.Имя;
            Результат.Вставить(Элемент.ПолноеИмя, Новый ДвоичныеДанные(ПутьКФайлу));
            УдалитьФайлы(ПутьКФайлу);
        КонецЦикла;

        Архив.Закрыть();
    Исключение
        Если Архив <> Неопределено Тогда
            Архив.Закрыть();
        КонецЕсли;
        УдалитьВременное(ИмяАрхива);
        УдалитьВременное(КаталогРаспаковки);
        ВызватьИсключение;
    КонецПопытки;

    УдалитьВременное(ИмяАрхива);
    УдалитьВременное(КаталогРаспаковки);
    Возврат Результат;

КонецФункции
  • Сумма НесжатыйРазмер считается до извлечения: архив в мегабайт может распаковаться в гигабайты и занять диск сервера.
  • РежимВосстановленияПутейФайловZIP.НеВосстанавливать кладёт файл прямо в каталог распаковки, поэтому имя вида ..\..\ не выведет его за пределы временного каталога.
  • Каждый файл сразу читается в ДвоичныеДанные и удаляется — одинаковые имена из разных папок архива не мешают друг другу. Ключ результата — ПолноеИмя, путь внутри архива.
  • ЧтениеZipФайла закрываем и при ошибке, иначе временный архив останется занятым и не удалится. Конструктор принимает и поток: Новый ЧтениеZipФайла(ДанныеАрхива.ОткрытьПотокДляЧтения()) обходится без временного файла архива.
  • XML из результата удобнее читать через ЧтениеXML: кодировку он берёт из заголовка файла.

Файл с клиента на сервер и обратно

Пользователь выбирает ZIP, сервер распаковывает его и возвращает протокол, клиент предлагает протокол сохранить.

// Модуль формы обработки «Загрузка заказов из ZIP». Платформа 8.3.18 и новее.

&НаКлиенте
Асинх Процедура ЗагрузитьАрхив(Команда)

    ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
    ПараметрыДиалога.Фильтр = "Архив ZIP (*.zip)|*.zip";

    // Диалог выбора и помещение во временное хранилище; веб-клиенту расширение не нужно
    Помещенный = Ждать ПоместитьФайлНаСерверАсинх(, , , ПараметрыДиалога, УникальныйИдентификатор);
    Если ТипЗнч(Помещенный) <> Тип("ОписаниеПомещенногоФайла") Или Помещенный.ПомещениеФайлаОтменено Тогда
        Возврат;
    КонецЕсли;

    АдресПротокола = ОбработатьАрхивНаСервере(Помещенный.Адрес, Помещенный.СсылкаНаФайл.Имя,
        УникальныйИдентификатор);

    ПараметрыСохранения = Новый ПараметрыДиалогаПолученияФайлов;
    ПараметрыСохранения.Заголовок = "Сохранить протокол загрузки";
    Ждать ПолучитьФайлССервераАсинх(АдресПротокола, "Протокол.csv", ПараметрыСохранения);

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

&НаСервереБезКонтекста
Функция ОбработатьАрхивНаСервере(АдресАрхива, ИмяАрхива, ИдентификаторФормы)

    ДанныеАрхива = ПолучитьИзВременногоХранилища(АдресАрхива);
    УдалитьИзВременногоХранилища(АдресАрхива);
    Если ТипЗнч(ДанныеАрхива) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Файл не получен, выберите его ещё раз";
    КонецЕсли;

    Протокол = Новый Массив;
    Протокол.Добавить("Архив;" + ИмяАрхива);
    Протокол.Добавить("Файл;Размер, байт");
    Для Каждого КлючИЗначение Из ФайлыСервер.РаспаковатьZip(ДанныеАрхива, ".xml") Цикл
        // здесь разбор XML и создание документов
        Протокол.Добавить(КлючИЗначение.Ключ + ";" + Формат(КлючИЗначение.Значение.Размер(), "ЧГ=0; ЧН=0"));
    КонецЦикла;

    ТекстПротокола = СтрСоединить(Протокол, Символы.ВК + Символы.ПС);
    ДанныеПротокола = ПолучитьДвоичныеДанныеИзСтроки(ТекстПротокола, "windows-1251");
    Возврат ПоместитьВоВременноеХранилище(ДанныеПротокола, ИдентификаторФормы);

КонецФункции
  • ПоместитьФайлНаСерверАсинх с параметрами диалога кладёт выбранный файл во временное хранилище, расширение веб-клиенту не нужно. С путём на клиенте вместо параметров диалога файл помещается без диалога, но в веб-клиенте тогда нужно расширение.
  • УникальныйИдентификатор формы привязывает данные в хранилище к форме: они живут, пока форма открыта. Сервер удаляет архив из хранилища сразу после чтения — он может быть большим.
  • Проверяем и тип результата, и флаг ПомещениеФайлаОтменено. СсылкаНаФайл.Имя — имя без пути; СсылкаНаФайл.Файл в веб-клиенте без расширения равен Неопределено.

Какой метод выбрать под версию платформы:

Задача8.3.18 и новее8.3.15–8.3.17БСП
Файл на серверПоместитьФайлНаСерверАсинхНачатьПомещениеФайлаНаСерверФайловаяСистемаКлиент.ЗагрузитьФайл
Несколько файлов на серверПоместитьФайлыНаСерверАсинхНачатьПомещениеФайловНаСерверФайловаяСистемаКлиент.ЗагрузитьФайлы
Файл с сервераПолучитьФайлССервераАсинхНачатьПолучениеФайлаССервераФайловаяСистемаКлиент.СохранитьФайл

Методы Начать… принимают обработчик ОписаниеОповещения, например НачатьПомещениеФайлаНаСервер(Оповещение, , , , ПараметрыДиалога, УникальныйИдентификатор). В конфигурации на БСП проще вызвать ФайловаяСистемаКлиент — модуль сам выбирает способ под клиент и платформу.

// Тот же сценарий через БСП. ОбработатьАрхивНаСервере — из предыдущего листинга.

&НаКлиенте
Процедура ЗагрузитьАрхивБСП(Команда)

    ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
    ПараметрыЗагрузки.ИдентификаторФормы = УникальныйИдентификатор;
    ПараметрыЗагрузки.Диалог.Фильтр = "Архив ZIP (*.zip)|*.zip";
    Оповещение = Новый ОписаниеОповещения("ЗагрузитьАрхивБСПЗавершение", ЭтотОбъект);
    ФайловаяСистемаКлиент.ЗагрузитьФайл(Оповещение, ПараметрыЗагрузки);

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

&НаКлиенте
Процедура ЗагрузитьАрхивБСПЗавершение(ПомещенныйФайл, ДополнительныеПараметры) Экспорт

    Если ПомещенныйФайл = Неопределено Тогда
        Возврат; // пользователь отказался от выбора
    КонецЕсли;

    АдресПротокола = ОбработатьАрхивНаСервере(ПомещенныйФайл.Хранение, ПомещенныйФайл.Имя,
        УникальныйИдентификатор);
    ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, АдресПротокола, "Протокол.csv");

КонецПроцедуры
  • ЗагрузитьФайл передаёт в обработчик Неопределено при отказе или структуру с полями Хранение (адрес во временном хранилище) и Имя. В тонком клиенте Имя — полный путь на компьютере пользователя: на сервере он годится только как подпись.
  • СохранитьФайл(Обработчик, Адрес, ИмяФайла) — обратная операция; если реакция на завершение не нужна, первым параметром передают Неопределено.
  • Серверные аналоги УдалитьВременное в БСП — ФайловаяСистема.СоздатьВременныйКаталог, УдалитьВременныйКаталог, УдалитьВременныйФайл.

Типичные ошибки

  • Серверу передают путь с компьютера пользователя. Существует() на сервере возвращает Ложь, а ЧтениеТекста падает с «Ошибка при вызове конструктора (ЧтениеТекста)». Передавайте содержимое через временное хранилище.
  • «Использование синхронных методов на клиенте запрещено». Свойство конфигурации «Режим использования синхронных вызовов расширений платформы и внешних компонент» не разрешает синхронные вызовы, а на клиенте вызван Существует() или НайтиФайлы(). Замените их на СуществуетАсинх() и НайтиФайлыАсинх() или перенесите работу на сервер.
  • «Отказано в доступе» при записи с сервера. Служба 1С работает под своей учётной записью, а не под пользователем базы, — права на каталог нужны ей.
  • «Процесс не может получить доступ к файлу, так как этот файл занят другим процессом». Файл открыт в Excel или ваш код не закрыл ЗаписьТекста либо ЧтениеZipФайла. Закрывайте объекты в обеих ветках Попытка.
  • Вместо ошибки — нечитаемый текст. Файл в UTF-8, прочитанный как Windows-1251, превращает «Привет» ⠫Привет». Платформа об этом не сообщает: кодировку нужно знать заранее.

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

Почему в файловой базе всё работало, а на сервере файл не находится?

В файловом варианте серверный код выполняется на компьютере пользователя, и локальный путь там существует. В клиент-серверном тот же код работает на сервере 1С, и C:\Обмен\ — уже папка сервера. Выбор файла — на клиенте, обработка — на сервере, между ними — временное хранилище.

Как с сервера 1С записать файл в сетевую папку?

Только по UNC-пути вида \\fileserver\obmen\, не через букву диска. Права на запись нужны учётной записи, от которой запущен сервер 1С: по умолчанию USR1CV8 в Windows и usr1cv8 в Linux. В Linux сетевую папку сначала монтируют, и путь будет вида /mnt/obmen/.

Как определить кодировку текстового файла?

Надёжно — только по договорённости с отправителем. Первые байты EF BB BF означают UTF-8 с BOM, FF FE — UTF-16. Без BOM помогает проверка на образце: если русский текст читается как «РџСЂРёРІРµС‚», файл в UTF-8, а вы открываете его как 1251.

Когда проще заказать

Обмен через каталоги с журналом, загрузку архивов от поставщиков или выгрузку для банка в жёстком формате быстрее поручить исполнителю, который уже решал такие задачи, — посмотрите услуги по доработке 1С. Опишите формат файлов и где работает база в форме «Разместить задание» — исполнители оценят объём и сроки.

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.