Создать, прочитать, скопировать или удалить файл 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") — файлы по маске, сам каталог остаётся. Корзины нет: удалённое не восстановить.Кодировку указывайте всегда, даже если она совпадает со значением по умолчанию.
// Общий модуль ФайлыСервер.
// Выгружает прайс в 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 и возвращает архив как ДвоичныеДанные.
// Файлы — соответствие: ключ — имя файла в архиве без каталогов,
// значение — ДвоичныеДанные или Строка (запишется в UTF-8 без BOM).
Функция УпаковатьВZip(Файлы) Экспорт
КаталогФайлов = КаталогВременныхФайлов() + "zip_" + Строка(Новый УникальныйИдентификатор)
+ ПолучитьРазделительПути();
ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
СоздатьКаталог(КаталогФайлов);
Попытка
Архив = Новый ЗаписьZipФайла(ИмяАрхива, , , , УровеньСжатияZIP.Максимальный);
Для Каждого КлючИЗначение Из Файлы Цикл
Данные = КлючИЗначение.Значение;
Если ТипЗнч(Данные) = Тип("Строка") Тогда
Данные = ПолучитьДвоичныеДанныеИзСтроки(Данные, "UTF-8", Ложь);
КонецЕсли;
ПолноеИмя = КаталогФайлов + КлючИЗначение.Ключ;
Данные.Записать(ПолноеИмя);
Архив.Добавить(ПолноеИмя, РежимСохраненияПутейZIP.НеСохранятьПути);
КонецЦикла;
Архив.Записать();
Результат = Новый ДвоичныеДанные(ИмяАрхива);
Исключение
УдалитьВременное(КаталогФайлов);
УдалитьВременное(ИмяАрхива);
ВызватьИсключение;
КонецПопытки;
УдалитьВременное(КаталогФайлов);
УдалитьВременное(ИмяАрхива);
Возврат Результат;
КонецФункции
// Удаляет временный файл или каталог. Ошибку не пробрасывает, а пишет в журнал:
// неудачная уборка не должна отменять готовый результат.
Процедура УдалитьВременное(Путь)
Попытка
УдалитьФайлы(Путь);
Исключение
ЗаписьЖурналаРегистрации("Файлы.Временные", УровеньЖурналаРегистрации.Предупреждение, , ,
Путь + Символы.ПС + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
КаталогВременныхФайлов() возвращает путь с разделителем на конце. Каталог общий для всех сеансов рабочего процесса, поэтому подкаталог получает уникальное имя.ПолучитьИмяВременногоФайла("zip") только придумывает уникальное имя в этом каталоге и файл не создаёт. Платформа временные файлы за вас не удаляет, а блока «finally» в языке нет — уборка повторена в ветке Исключение перед ВызватьИсключение.ДвоичныеДанные через временное хранилище.Архив.Добавить(Каталог + ПолучитьМаскуВсеФайлы(), РежимСохраненияПутейZIP.СохранятьОтносительныеПути, РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно).Архив от пользователя или контрагента — недоверенные данные: сначала проверяем объём, потом извлекаем только нужные файлы.
// Общий модуль ФайлыСервер. УдалитьВременное — из предыдущего листинга.
// Извлекает из ZIP файлы с нужным расширением.
// Возвращает соответствие: путь внутри архива — ДвоичныеДанные файла.
Функция РаспаковатьZip(ДанныеАрхива, Расширение = ".xml", ЛимитБайт = 104857600) Экспорт
ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
КаталогРаспаковки = ПолучитьИмяВременногоФайла() + ПолучитьРазделительПути();
ДанныеАрхива.Записать(ИмяАрхива);
СоздатьКаталог(КаталогРаспаковки);
Результат = Новый Соответствие;
Архив = Неопределено;
Попытка
Архив = Новый ЧтениеZipФайла(ИмяАрхива);
Всего = 0;
Для Каждого Элемент Из Архив.Элементы Цикл
Всего = Всего + Элемент.НесжатыйРазмер;
КонецЦикла;
Если Всего > ЛимитБайт Тогда
ВызватьИсключение СтрШаблон("Архив распаковывается в %1 байт, допустимо %2",
Формат(Всего, "ЧГ=0"), Формат(ЛимитБайт, "ЧГ=0"));
КонецЕсли;
Для Каждого Элемент Из Архив.Элементы Цикл
Если Не СтрЗаканчиваетсяНа(НРег(Элемент.Имя), НРег(Расширение)) Тогда
Продолжить; // каталоги и файлы других типов
КонецЕсли;
Архив.Извлечь(Элемент, КаталогРаспаковки, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
ПутьКФайлу = КаталогРаспаковки + Элемент.Имя;
Результат.Вставить(Элемент.ПолноеИмя, Новый ДвоичныеДанные(ПутьКФайлу));
УдалитьФайлы(ПутьКФайлу);
КонецЦикла;
Архив.Закрыть();
Исключение
Если Архив <> Неопределено Тогда
Архив.Закрыть();
КонецЕсли;
УдалитьВременное(ИмяАрхива);
УдалитьВременное(КаталогРаспаковки);
ВызватьИсключение;
КонецПопытки;
УдалитьВременное(ИмяАрхива);
УдалитьВременное(КаталогРаспаковки);
Возврат Результат;
КонецФункции
НесжатыйРазмер считается до извлечения: архив в мегабайт может распаковаться в гигабайты и занять диск сервера.РежимВосстановленияПутейФайловZIP.НеВосстанавливать кладёт файл прямо в каталог распаковки, поэтому имя вида ..\..\ не выведет его за пределы временного каталога.ДвоичныеДанные и удаляется — одинаковые имена из разных папок архива не мешают друг другу. Ключ результата — ПолноеИмя, путь внутри архива.ЧтениеZipФайла закрываем и при ошибке, иначе временный архив останется занятым и не удалится. Конструктор принимает и поток: Новый ЧтениеZipФайла(ДанныеАрхива.ОткрытьПотокДляЧтения()) обходится без временного файла архива.Чтение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");
КонецПроцедуры
ЗагрузитьФайл передаёт в обработчик Неопределено при отказе или структуру с полями Хранение (адрес во временном хранилище) и Имя. В тонком клиенте Имя — полный путь на компьютере пользователя: на сервере он годится только как подпись.СохранитьФайл(Обработчик, Адрес, ИмяФайла) — обратная операция; если реакция на завершение не нужна, первым параметром передают Неопределено.УдалитьВременное в БСП — ФайловаяСистема.СоздатьВременныйКаталог, УдалитьВременныйКаталог, УдалитьВременныйФайл.Существует() на сервере возвращает Ложь, а ЧтениеТекста падает с «Ошибка при вызове конструктора (ЧтениеТекста)». Передавайте содержимое через временное хранилище.Существует() или НайтиФайлы(). Замените их на СуществуетАсинх() и НайтиФайлыАсинх() или перенесите работу на сервер.ЗаписьТекста либо ЧтениеZipФайла. Закрывайте объекты в обеих ветках Попытка.В файловом варианте серверный код выполняется на компьютере пользователя, и локальный путь там существует. В клиент-серверном тот же код работает на сервере 1С, и C:\Обмен\ — уже папка сервера. Выбор файла — на клиенте, обработка — на сервере, между ними — временное хранилище.
Только по 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С. Опишите формат файлов и где работает база в форме «Разместить задание» — исполнители оценят объём и сроки.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.