Новое в версии 2020.2.1

В версии 2020.2.1 мы упростили работу с сертификатами при подключении к серверу системы взаимодействия, реализовали работу с вложениями электронной почты, реализовали поддержку конвейеров (pipes), реализовали установку тела HTTP-запроса из потока и файла, реализовали сериализацию объектов языка 1С:Исполнителя в формат JSON и десериализацию, реализовали файловую работу с ZIP-архивами, реализовали другие возможности и исправили ошибки.

Система взаимодействия

Проверка сертификатов при подключении к серверу системы взаимодействия

Мы реализовали проверку сертификатов при установке соединения с сервером системы взаимодействия (СистемаВзаимодействия.Подключиться()). Если проверка сертификата закончилась неудачей, то попытка подключения будет завершена исключением ИсключениеСистемыВзаимодействия.

В целях отладки работы приложения по прежнему можно воспользоваться методом СистемаВзаимодействия.ПодключитьсяБезПроверкиСертификата, но мы не рекомендуем пользоваться этим методом в реальной эксплуатации.

Проверка сертификатов через хранилище сертификатов Java

Для упрощения работы мы реализовали возможность подключения к серверу системы взаимодействия без указания параметров ФайлХранилища, ПарольХранилища и ПарольКлюча в методе СистемаВзаимодействия.Подключиться(). Это возможно в том случае, если сертификат, используемый на сервере системы взаимодействия, подписан (выдан) доверенным удостоверяющим центром. Тогда будет использована встроенная проверка сертификата сервера с использованием входящих в его поставку jre сертификатов.

Если проверку сертификата, используемого на сервере, нельзя провести с использованием встроенных в java сертификатов, вызов завершится исключением, а для успешного подключения необходимо будет указать параметры хранилища.

Поддержка файлов сертификатов в формате pkcs12

Теперь в параметре ФайлХранилища (СистемаВзаимодействия.Подключиться()) вы можете указывать путь к сертификату сервера взаимодействия формата pkcs12. Раньше поддерживался только формат jks.

Электронная почта

Вложения электронной почты

Мы реализовали добавление вложений электронной почты и работу с ними. Почтовое вложение - это объект нового типа ВложениеЭлектроннойПочты, который обладает собственным набором характеристик. Сообщение электронной почты может содержать как одно, несколько вложений, а также не содержать вложений вообще. Тип ВложениеЭлектроннойПочты является общим как для исходящего, так и входящего сообщения.

Для того, чтобы работать с вложениями, мы реализовали несколько новых методов у типа ИсходящееСообщениеЭлектроннойПочты:
  • ПриложитьФайл() — добавляет файл во вложение. В параметре вы можете передать путь к файлу (Строка) или сам файл (Файл),
  • ПриложитьДанные() — в качестве источника данных можно указать объекты типов Строка, ПотокЧтения или Байты,
  • УдалитьВложение() — удаляет существующее вложение. В параметре нужно передать идентификатор (Ууид) вложения.

Для хранения вложений мы реализовали новое свойство ИсходящееСообщениеЭлектроннойПочты.Вложения. Это массив объектов типа ВложениеЭлектроннойПочты.

Сам тип ВложениеЭлектроннойПочты имеет свойства, описывающие вложение: Идентификатор (Ууид), Название (Строка), Данные (Байты) - собственно сами данные вложения и ТипСодержимого (Строка) - MIME тип вложения, который соответствует заголовку Content-Type.

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

При добавлении вложения в исходящее сообщение Идентификатор вложения будет сгенерирован автоматически.

При загрузке данных (ПриложитьДанные() типов Байты или ПотокЧтения), если вы не задали название вложения, в качестве названия будет использовано значение по умолчанию - Attachment. Если таких файлов будет несколько, это является допустимым.

При загрузке файла (ПриложитьФайл()) будет выполнена попытка получить все незаполненные свойства из свойств файла (название, тип содержимого).

ВложениеЭлектроннойПочты не имеет конструктора. Объект типа ВложениеЭлектроннойПочты нужен для присоединения к исходящему сообщению или для описания вложения во входящем сообщении. Таким образом, его использование неотделимо от объекта сообщения электронной почты и нет необходимости в отдельных конструкторах ВложениеЭлектроннойПочты. Для создания вложения вы можете использовать методы ИсходящееСообщениеЭлектроннойПочты.ПриложитьФайл() и ИсходящееСообщениеЭлектроннойПочты.ПриложитьДанные().

Ниже приведен пример добавления файла в исходящее письмо.
// Пример 1. Приложить файл к письму
метод ПриложитьФайлКПисьму()
    // 1. Подготовить письмо
    пер Сообщение = ИсходящееСообщениеЭлектроннойПочты("recipient@1c.ru")
    Сообщение.ДобавитьПолучателей("sender@1c.ru")
    Сообщение.Тема = "Тема сообщения электронной почты"
    Сообщение.Текст = "Текст сообщения электронной почты"
     
    // 2. Добавить вложения
    Сообщение.ПриложитьФайл("C:\Documents\Doc1.docx", "Приложение к письму.docx")
    Сообщение.ПриложитьФайл("C:\Documents\Вложение.xlsx")
 
    // 3. Отправить письмо
    пер ПараметрыПодключения = ПолучитьПараметрыПодключенияSmtp()
    КлиентSmtp.Отправить(ПараметрыПодключения, Сообщение)
;
 
// Пример 2. Добавить файл во вложения
метод ДобавитьФайлВоВложение()
    // 1. Подготовить письмо
    пер Сообщение = ИсходящееСообщениеЭлектроннойПочты("recipient@1c.ru")
    Сообщение.ДобавитьПолучателей("sender@1c.ru")
    Сообщение.Тема = "Тема сообщения электронной почты"
    Сообщение.Текст = "Текст сообщения электронной почты"
 
    // 2. Добавить вложение
    пер ФайлДляОтправки = новый Файл("C:\Documents\Doc1.pdf")
    Сообщение.ПриложитьДанные(ФайлДляОтправки.ОткрытьПотокЧтения(), "Приложение к письму.pdf", "application/pdf")
 
    // 3. Отправить письмо
    пер ПараметрыПодключения = ПолучитьПараметрыПодключенияSmtp()
    КлиентSmtp.Отправить(ПараметрыПодключения, Сообщение)
;

Работа с процессами операционной системы

Поддержка конвейеров (pipes)

Конвейер (pipe) — это способ межпроцессного взаимодействия, при котором выходной поток одного процесса является входным потоком для другого. Теперь вы можете создавать конвейеры с помощью нового метода ПроцессОС.ПередатьВыводВ(). Он добавляет новый процесс в конвейер на основе команды и аргументов. К процессу в конвейере будут применены те же настройки, что и к исходному ПроцессОс. Метод возвращает текущий экземпляр ПроцессОс, в котором выходной поток соответствует выходному потоку нового процесса.

Возможная проблема: Для корректной работы метода необходимо, чтобы объект работал в окружении Java9+.

Ниже приведен пример просмотра папки и поиска подстроки в Windows.

метод ПросмотретьПапкуИНайтиПодстроку(ПапкаДляПросмотра: Строка, Фильтр: Строка): Строка
    // Аналог ls в windows
    пер Процесс = новый ПроцессОс("cmd.exe", ["/c", "dir " + ПапкаДляПросмотра])
    
    // Передадим вывод аналогу grep в windows
    Процесс.ПередатьВыводВ("cmd.exe", ["/c", "findstr " + Фильтр])

    // Запустим конвейер
    Процесс.Запустить()

    возврат Процесс.ПолучитьПотокВывода().ПрочитатьКакТекст()
;

ПроцессОС.ПолучитьПотокВвода()

Мы реализовали метод ПроцессОС.ПолучитьПотокВвода(), который возвращает объект типа ПотокЗаписи. В него вы можете записывать текст, который будет передан объекту типа ПроцессОС.
пер ВходныеДанные = Процесс.ПолучитьПотокВвода()
ВходныеДанные.Записать("Текст как входные данные Процесса")

ПолучитьПотокВвода() можно вызвать только после запуска ПроцессОС. Пока вы не закроете полученный таким образом ПотокЗаписи, ПроцессОС будет ожидать входные данные.

Ниже приведен пример передачи строки поиска командному интерпретатору cmd.
метод Grep(Вход: Строка, Фильтр: Строка): Строка
    // Аналог grep в win. Требует входных данных
    пер Процесс = новый ПроцессОс(cmd.exe", ["/c", "findstr " + Filter])
    
    // Указать входные данные можно только после старта процесса
    Процесс.Запустить()

    область
        исп Поток = Процесс.ПолучитьПотокВвода()
        Поток.Записать(Вход)
    ; // Даем понять, что входных данных процесс может больше не ожидать.

    возврат Процесс.ПолучитьПотокВывода().ПрочитатьКакТекст()
;

Получение потока вывода и потока ошибок

В тип ПроцессОс мы добавили два новых метода - ПолучитьПотокВывода() и ПолучитьПотокОшибок(). Они имеют такое же назначение, как и старые свойства ПотокВывода и ПотокОшибок.

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

ПроцессОс.ПотокиОшибокИВыводаСоединены

Мы реализовали свойство ПроцессОс.ПотокиОшибокИВыводаСоединены. В том случае, когда объект типа ПроцессОс получен вами извне (вы не создавали его в своем коде), это свойство позволяет узнать, в какой поток направляются ошибки:

  • Истина - ошибки направляются в стандартный поток вывода (System.out),
  • Ложь - ошибки направляются в стандартный поток ошибок (System.err).

Напоминаем, что управлять направлением ошибок вы можете в конструкторе ПроцессОс с помощью параметра СоединитьПотокиОшибокИВывода. Стандартно потоки соединены и ошибки направляются в стандартный поток вывода.

Работа с HTTP

Установка тела HTTP-запроса из потока и файла

Мы реализовали возможность установить тело объекта ЗапросHttp из потока или файла. Эту возможность вы можете использовать для отправки больших файлов. Для этого у типа ЗапросHttp мы реализовали три новых метода:
  • УстановитьТело(Поток: ПотокЧтения): ЗапросHttp
  • УстановитьТело(Поток: ПотокЧтения, Размер: Число): ЗапросHttp
  • УстановитьТело(Файл: Файл): ЗапросHttp

При использовании метода УстановитьТело(ПотокЧтения) запрос будет выполнен с использованием Chunked transfer encoding.

При использовании всех этих методов само чтение будет осуществляться только в момент вызова метода ЗапросHttp.Выполнить().

Методы, устанавливающие тело из потока, после выполнения отправки закрывают переданный поток.

Ошибка перенаправления в HTTP-клиенте

В КлиентHttp мы исправили ошибку, которая выражалась в том, что в некоторых случаях не выполнялось перенаправление.

Работа с JSON

Сериализация объектов языка 1С:Исполнителя в формат JSON и десериализация

Мы реализовали сериализацию объектов языка 1С:Исполнителя в формат JSON и обратную операцию — десериализацию. Основным типом для выполнения этих операций является новый тип СериализацияJson. Объект этого типа вы можете получить из свойства глобального контекста СериализацияJson. Методы этого типа позволяют:

  • прочитать значение JSON в объект типа, поддерживаемого «1С:Исполнителем»ПрочитатьОбъект(),
  • прочитать значение JSON в СоответствиеПрочитатьСоответствие(),
  • прочитать значение JSON в МассивПрочитатьМассив(),
  • записать объект типа, поддерживаемого «1С:Исполнителем», в значение JSON в поток — ЗаписатьОбъект(ПотокЗаписи, Объект, НастройкиЗаписиОбъектовJson),
  • записать объект типа, поддерживаемого «1С:Исполнителем», в значение JSON в строку — ЗаписатьОбъект(Объект, НастройкиЗаписиОбъектовJson): Строка,

Для настройки сериализации и десериализации мы реализовали новые типы настроек со свойствами. Объекты этих типов используются в перечисленных выше методах:

  • тип НастройкиЧтенияОбъектовJson:
    • Кодировка — кодировка, которая будет использована при чтении из потока,
    • ПсевдонимыCвойств — псевдонимы для имени свойства JSON для конкретного свойства структуры,
    • ИгнорироватьНеизвестныеСвойства — признак игнорирования неизвестных (лишних) полей в тексте JSON.
  • тип НастройкиЗаписиОбъектовJson:
    • ИспользуемыеИменаСвойств — устанавливает признак изменения записываемого имени свойства по аналогии с @JsonProperty,
    • ИгнорируемыеСвойства — устанавливает признак игнорирования в результирующем объекте JSON определенных свойств,
    • ЗаписьСвойствБезОбработки — свойства, которые будут записаны без обработки («как есть»),
    • РежимЗаписиТипаЗначенияJson — способ записи информации о типе значения.

В ЧтениеJson мы добавили новые методы для чтения значения JSON в один из конкретных типов:

  • ПрочитатьСодержимоеКакДата(),
  • ПрочитатьСодержимоеКакВремя(),
  • ПрочитатьСодержимоеКакДлительность(),
  • ПрочитатьСодержимоеКакБайты().

Также в ЧтениеJson мы добавили новые свойства для определения текущей строки и текущего столбца в позиции чтения:

  • ТекущаяСтрока,
  • ТекущийСтолбец.

В типе ЗаписьJson мы изменили методы Записать(Типы) и Записать(Строка, Типы), добавив в состав типов, передаваемых в параметр, типы Дата, Время, Длительность, Байты и Неопределено.

Также мы добавили новое перечисление РежимЗаписиТипаЗначенияJson. Оно используется в методах СериализацияJson.ПрочитатьОбъект() и НастройкиЗаписиОбъектовJson.УстановитьРежимЗаписиТипаЗначенияJson().

Работа с ZIP

Файловая работа с ZIP-архивами

Ранее в «1С:Исполнителе» уже существовала возможность потоковой работы с ZIP-архивами с помощью типов ЧтениеZip и ЗаписьZip. Теперь, в дополнение к этому, мы реализовали возможность файловой работы с ZIP-архивами с помощью типа ФайлZip .

Вы можете получить объект этого типа с помощью конструктора, которому в качестве параметра нужно передать путь к будущему файлу архива. Закрывать объект не надо, все изменения архива сразу отображаются на диск.

ФайлZip имеет несколько методов для изменения архива:

  • Добавить(Строка | Файл) — добавляет в архив файл (по его пути или сам файл). Если путь указывает на каталог, добавляет каталог и его содержимое,
  • Добавить(ПотокЧтения) — добавляет в архив содержимое потока,
  • Удалить() - удаляет из архива файл или каталог со всем его содержимым,
  • УстановитьКомментарий() — устанавливает комментарий к архиву,
  • ПолучитьКомментарий() — возвращает комментарий к архиву.

Кроме этого ФайлZip имеет методы для чтения архива:

  • Извлечь(Строка | Файл) — распаковывает весь архив в указанный каталог,
  • Извлечь(ЭлементZip | Строка) — распаковывает элемент архива в указанный каталог,
  • Найти() — ищет все элементы архива по указанной подстроке, содержащейся в пути,
  • ЕстьЗашифрованныеФайлы() — возвращает Истина, если хотя бы один файл-элемент зашифрован,
  • Элементы() — возвращает все элементы архива.
Пример записи в ZIP-архив: |
метод ЗаписатьСШифрованием()

    // Создали объект взаимодействия с архивом
    пер Архив = новый ФайлZip(Файлы.ПолучитьДомашнийКаталог().Путь + "/archive.zip", "password") 

    // Благодаря паролю можно распаковывать файлы, если архив уже существует и файлы зашифрованы, а также добавлять
    // новые файлы в зашифрованном виде МетодШифрованияПоУмолчанию = МетодШифрованияZip.Zip20
 
    // Для новых файлов установим максимальный уровень сжатия, иначе значение будет Нормальный
    пер УровеньСжатияПоУмолчанию = УровеньСжатияZip.Максимальный 

    // Для новых файлов установим метод шифрования, иначе значение будет Zip20 (так как открыли архив с паролем)
    пер МетодШифрованияПоУмолчанию = МетодШифрованияZip.AES256 
     
    // Добавим папку с файлами
    Архив.Добавить(Файлы.ПолучитьДомашнийКаталог().Путь + "/ПапкаСФайламиДляСжатия", 
                   УровеньСжатияПоУмолчанию, МетодШифрованияПоУмолчанию) 
     
    пер ФайлДляСжатия = новый Файл("ФайлДляСжатия.txt", 
                                   Файлы.ПолучитьДомашнийКаталог())
 
    // Добавим в корень файл
    Архив.Добавить(ФайлДляСжатия, УровеньСжатияПоУмолчанию, МетодШифрованияПоУмолчанию); 
    
    // Можем добавить через поток
    Архив.ДобавитьИзПотока(ФайлДляСжатия.ОткрытьПотокЧтения(), "ПапкаСФайламиДляСжатия/ФайлДляСжатия_Копия", 
                           УровеньСжатияПоУмолчанию, МетодШифрованияПоУмолчанию) 
    Архив.Комментарий = "Архив с ПапкаСФайламиДляСжатия и файлом. Сделана копия. Пароль: password"
     
    // Закрывать Архив или сохранять изменения не нужно. Все команды работают сразу.
;
Пример распаковки зашифрованного архива:
// Допустим мы не знаем является ли архив зашифрованным или нет. 
// В таком случае мы все равно сможем посмотреть его элементы без их содержимого. Воспользуемся этим
метод ИзвлечьНеизвестныйАрхив(Путь: Строка)

    // Не знаем изначально файлы архива зашифрованы или нет.
    пер ПроверочныйАрхив = новый ФайлZip(Путь)
    пер АрхивДляРаботы = Неопределено
     
    если ПроверочныйАрхив.Зашифрован() 
    
        // Создали новый объект с паролем для возможности распаковки содержимого.
        АрхивДляРаботы = новый ФайлZip(Путь, "possible_password") 
        
    иначе
        АрхивДляРаботы = ПроверочныйАрхив
    ;
    // Аналог: получаем все элементы (.Элементы()), 
    // если не Элемент.ЯвляетсяКаталогом() смотрим на Элемнет.Зашифрован() (см. описание объекта)
 
    АрхивДляРаботы.ИзвлечьВсе(Файлы.ПолучитьДомашнийКаталог().Путь)
     
    // Если нужен один файл.
    АрхивДляРаботы.Извелчь("ВыбранныйФайл.txt", Файлы.ПолучитьДомашнийКаталог().Путь)
;
 
// Если мы не знаем зашифрован ли архив или нет, то можно создать объект ZipФайл с паролем в конструкторе. 
// Так для обычных и зашифрованных элементов распаковка пройдет корректно.
Пример поиска и перезаписи файла в архиве.
метод НайтиИПереписатьФайл(ПутьКАрхиву: Строка, ИмяФайла: Строка, НовыеДанные: ПотокЧтения)
    пер Архив = новый ФайлZip(ПутьКАрхиву)
 
     // Не помним точный путь к файлу в архиве, но помним имя.
    пер Элементы = Архив.Найти(ИмяФайла) 
    если Элементы.Размер() > 1
    
        // Файл с таким именем не один, нужно уточнить путь
        Консоль.Записать("Файл с таким именем не один, нужно уточнить путь")
        возврат
    ;
 
    пер ИскомыйЭлемент = Элементы.Получить(0)
    Консоль.Записать("Удаляем старый файл из архива со временем изменения: " + ИскомыйЭлемент.ВремяИзменения)
    пер ПутьКЭлементуВАрхиве = ИскомыйЭлемент.ПутьВАрхиве
     
    // Заменяем файл.
    Архив.Удалить(ИскомыйЭлемент)
    пер КолВо = Архив.Элементы().Размер()
    Архив.Добавить(НовыеДанные, ПутьКЭлементуВАрхиве, УровеньСжатия.Максимальный)
 
    // Убедимся, что файл в архиве.
    если КолВо + 1 = Архив.Элементы().Размер()
        Консоль.Записать("Операция замены успешна")
    ;
;

Прочее

Поддержка шебанга (shebang)

Шебанг (shebang) - последовательность из двух управляющих символов «#!» в начале файла скрипта в ОС Linux. Загрузчик программ рассматривает остаток строки после шебанга как имя файла программы-интерпретатора. Загрузчик запускает эту программу и передает ей в качестве параметра имя файла скрипта с шебангом.

Мы реализовали поддержку шебанга в «1С:Исполнителе» в ОС Linux. Таким образом, если раньше для запуска скрипта вы писали, например:
/usr/bin/executor/executor.sh myscript.xbsl 
то теперь в начало скрипта myscript.xbsl вы можете добавить строку #!/usr/bin/executor:
#!/usr/bin/executor
 
method Script()
    Console.Write("Hello")
;
и запускать скрипт вот таким образом:
.\myscript.xbsl

Компилятор «1С:Исполнителя» игнорирует строки в начале скрипта, начинающиеся с «#!».

Кодировка в методе ПотокЧтения.ПрочитатьКакТекст()

При чтении потока вывода из консоли существует возможность столкнуться с неправильной кодировкой символов кириллицы. Для решения этой проблемы в методе ПотокЧтения.ПрочитатьКакТекст() мы реализовали параметр Кодировка. С его помощью вы можете задать нужную кодировку.