Пример загрузки/выгрузки файлов на SFTP сервер из 1С

К сожалению 1С пока не позволяет своими средствами обмениваться файлами с SFTP сервером.
Столкнувшись с этой проблемой, оптимальным для себя выбрал вариант с использованием бесплатного SFTP клиента:WinSCP.
Я не нашел в сети примеров работы 1С с этой утилитой через COM-соединение, поэтому выкладываю свой. Возможно кому-то будет полезен.

Первом делом необходимо скачать установочный пакет (можно так же использовать portable-версию) и COM-библиотеку с сайта WinSCP и зарегистрировать ее:

%WINDIR%Microsoft.NETFrameworkверсияRegAsm.exe WinSCP.dll /codebase /tlb

Подробнее об установке здесь

Теперь можно работать с ней из 1С: 

//СОЕДИНЕНИЕ
Попытка

//Задаем параметры подключения
sessionOptions = Новый COMОбъект("WinSCP.SessionOptions"); //Создаем объект SessionOptions
sessionOptions.HostName = "example.com";
sessionOptions.UserName = "user";
sessionOptions.Password = "mypassword";
sessionOptions.SshHostKeyFingerprint = "ssh-rsa 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx";


session = Новый COMОбъект("WinSCP.Session"); //Создаем объект Session

//параметр необходимо использовать если пути регистрации DLL и исполняемого файла различны
session.ExecutablePath = "C:Program Files (x86)WinSCPwinscp.exe";

// Подключаемся
session.Open(sessionOptions);
Исключение
Сообщить(ОписаниеОшибки());
Возврат;
КонецПопытки;

//ВЫГРУЗКА
Попытка
ПутьВыгрузки = Объект.КаталогВыгрузки+"*";
ПутьЗагрузкиНаФТП = Объект.КаталогЗагрузкиНаФТПСервере;

//Выгружаем файлы
transferResult = session.PutFiles(ПутьВыгрузки, ПутьЗагрузкиНаФТП);

//Проверяем результат на возможные ошибки
transferResult.Check();

//Обрабатываем результат выгрузки
Для каждого ВыгруженныйФайл Из transferResult.Transfers Цикл
Сообщить("Выгружен файл: "+ВыгруженныйФайл.FileName);
ПереместитьФайл(ВыгруженныйФайл.FileName, ХранилищеВыгруженныхФайлов);
КонецЦикла;
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;

//ЗАГРУЗКА
Попытка
ПутьЗагрузки = Объект.КаталогЗагрузки+"*";
ПутьВыгрузкиНаФТП = Объект.КаталогВыгрузкиНаФТПСервере;

//Загружаем файлы с удаленного сервера
transferResult = session.GetFiles(ПутьВыгрузкиНаФТП, ПутьЗагрузки);

//Проверяем возможные ошибки
transferResult.Check();

//Обрабатываем результат
Для каждого ЗагруженныйФайл Из transferResult.Transfers Цикл
Сообщить("Загружен файл: "+ЗагруженныйФайл.FileName);
session.RemoveFiles(ЗагруженныйФайл.FileName); //Удаляем уже скаченные файлы
КонецЦикла;

Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;

//Разрываем соединение
session.Dispose();

Все необходимые файлы и пример обработки обмена во вложении.

Я привел пример только основных возможностей, которые сам использовал. У библиотеки довольно много классов и методов и при необходимости возможности использования можно значительно расширить. Мануал здесь

Пример работы с WinSCP через командную строку

71 Comments

  1. LexSeIch

    Мир этому дому!

    Спасибо за интересную информацию — взял на заметку. Отдельное спасибо за ссылки по теме — будем разбираться.

    Reply
  2. Vladuha

    Так ведь 8.3 умеет ЗащищенноеСоединениеOpenSSL

    Reply
  3. ram3

    Да действительно, заявлено что 8.3 умеет устанавливать FTPСоединение по SSL, не пробовал. Я привел рабочий пример для 8.2. Спасибо за информацию

    Reply
  4. awk

    (2) Vladuha, SFTP и FTPS — это разные вещи. SFTP — это фтп ssh сервера, а FTPS — это фтп через SSL/TLS.

    Reply
  5. Vladuha

    (4) awk, ваша правда, перепутал

    Reply
  6. vano-ekt

    норм, а я когда-то лет 7 назад для 8.1 настраивал какого-то ftp-клиента на сервере, прописывал профили, а потом вызывал через КомандаСистемы…

    COM — это хорошо

    а 8.3 — лучше 🙂

    Reply
  7. vano-ekt

    (4) о я тоже думал 8.3 SSL научили, а там тунели запилили

    Reply
  8. ram3

    (6) vano-ekt,

    Как выяснилось, 8.3 тоже не умеет работать с SFTP

    Reply
  9. Aragorn

    Спасибо, свое время тоже пришлось поизвращатся с sftp

    Reply
  10. d_control

    Добрый день!

    Очень благодарен за информацию!

    Только у меня не получается подключиться.

    Не пойму что нужно указать в поле «SshHostKeyFingerprint»

    где взять значение для этого поля?

    Через обычного клиента WinSCP подключаюсь нормально. Там просто указываю адрес, юзера и пароль.

    Reply
  11. d_control

    Всё, нашел… прошу прощения за неумный вопрос 🙂

    Reply
  12. cool.vlad4

    http://habrahabr.ru/company/Centrobit/blog/165441/

    Вывод: данная реализация позволяет передавать файлы из 1С: Предприятие 8.2. большого размера по защищенному протоколу SFTP. Плюс появляется возможность переносить часть функционала из 1С во внешнюю компоненту, что защищает написанный код и позволяет реализовывать дополнительный, не доступный 1С функционал.

    исходники открыты.

    Reply
  13. John83

    Установил приложение, зарегил библиотеку, но все равно при попытке создать COM-объект в 1С, ругается

    {Форма.Форма.Форма(17)}: Ошибка при вызове конструктора (COMОбъект): Класс не зарегистрирован: Класс не зарегистрирован

    Кто-нибудь сталкивался?

    Reply
  14. ram3

    (13) John83, NET Framework какой? Может это поможет: http://winscp.net/eng/docs/library_install#registering

    Reply
  15. sandybaev

    (11) d_control, что нашел?

    Reply
  16. sandybaev

    Ребята, а что таки писать в поле sessionOptions.SshHostKeyFingerprint ?

    я вот пишу так:

    sessionOptions.SshHostKeyFingerprint = «ssh-rsa 2048 67:13:89:75:aa:5f:b4:9b:e2:f2:da:87:41:a1:d2:d1»;

    система мне отвечает так:

    Соединение неожиданно разорвано. Сервер вернул код завершения команды 0.

    вот от куда беру код:

    Reply
  17. ram3

    (16) sandybaev,

    какая именно команда возвращает ошибку, .Open ? С этими же параметрами через саму программу подключиться удается?

    Reply
  18. sandybaev

    (17) ram3, Все, брат. Получилось. В параметр SshHostKeyFingerprint Я передал публичный ключ сгенерированный самим sftp серваком. А ошибка подключения была в изменненом пароле администратора (я об этом узнал потом).

    Огромное спасибо вроде все заработало.

    ТОлько единственное не пойму зачем ты перемещаешь файл этой командой —

    ПереместитьФайл(ВыгруженныйФайл.FileName, ХранилищеВыгруженныхФайлов);

    Если на сервер ты уже закидываешь эти файлы командой

    session.PutFiles(ПутьВыгрузки, ПутьЗагрузкиНаФТП); ?

    Reply
  19. ram3

    (18) sandybaev,

    .PutFiles это выгрузка на сервер, а мне еще нужно было сохранять локально все успешно выгруженные файлы, поэтому я сначала проверял результат .Check() , а потом в цикле по коллекции результатов выгрузки сохранял эти же файлы локально, для истории

    Reply
  20. sandybaev

    (19) ram3, мм. сорри.

    Reply
  21. sandybaev

    (19) ram3,

    Не подскажешь.

    Как теперь я могу создавать и менять папки на sftp серваке.

    Просто тут пишу обработку для обмена а она по ТЗ должна уметь создавать и менять папки.

    Заранее спасибо.

    Reply
  22. ram3

    (21) sandybaev,

    создавать — CreateDirectory, читай мануалы http://winscp.net/eng/docs/library_session , думаю там все найдешь.

    и плюсани уж за публикацию)

    Reply
  23. sandybaev

    (22) ram3, Все, плюсанул вроде как. Почитаю на досуге. Спасибо большое. Тебе бы дальше эту тему развить. желательно с обилием скринов 🙂

    Reply
  24. kashafeev

    (22) ram3, отличная публикация! Есть вопрос по такой задаче: необходимо синхронизировать файлы командой SynchronizeDirectories. Пишу:

    transferResult = session.SynchronizeDirectories(Local, ПутьЗагрузкиЛокальный, ПутьКФайламНаСервере, Ложь, Ложь, , «*.wav»);

    Но не знаю, что ставить в первый параметр. По-идее, там должен быть класс SynchronizationMode mode (Например: SynchronizationMode.Local, SynchronizationMode.Remote and SynchronizationMode.Both).

    Как его объявить в 1С?

    Reply
  25. kashafeev

    (25) ram3, пробовал, не получилось. Есть ещё какие-нибудь предложения?

    Reply
  26. ram3

    (24) kashafeev,

    думаю можно так:

    SynchronizationMode = Новый COMОбъект(«WinSCP.SynchronizationMode»);

    но не уверен, надо пробовать.

    Reply
  27. ram3

    (26) kashafeev,

    а так:

    WinSCP = Новый COMОбъект(«WinSCP»);

    SynchronizationMode = WinSCP.SynchronizationMode;

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

    Reply
  28. Пользователь 1С

    Для 7.7 нечто подобное реально?

    Reply
  29. ram3

    (28) Пользователь 1С, почему нет? С COM Объектами 7.7 вроде как умеет. Код только немного переписать

    Reply
  30. krosaf4eg

    спасибо за чудесную реализацию!!!

    в сети навалом обработок, но все они работают через командную строку, а тут COM-соединение. То что доктор прописал )))) в благодарность скачал, хотя и качать ничего не нужно, все понятно из текста статьи

    Reply
  31. dagroma

    (26) kashafeev,

    SynchronizationMode mode: 0 — local, 1 — remote, , 2 — both

    SynchronizationCriteria criteria: 0 — None, 1 — Time, 2 — Size, 3 — Either

    Reply
  32. basta-one2007

    Спасибо большое. Статья очень помогла.

    Reply
  33. sandybaev

    ребята помогите

    есть коренвая директория сервера /public

    в ней я программно создаю поддиректорию командой session.CreateDirectory(«/public» + «ОбластьКонтрагента»)

    все ок, создается теперь надо дальше в директории области контрагента создать еще одну папку (последнюю) под названием «НаименованиеКонтрагента»

    как это сделать через функции WinSCPnet.dll?

    перерыл из форум и хэлп, ничего нет.

    Reply
  34. ferre

    Помогите

    Как подключится без пароля с приват ключем.

    sessionOptions = Новый COMОбъект(«WinSCP.SessionOptions»); //Создаем объект SessionOptions

    sessionOptions.HostName = «1.1.1.1»;

    sessionOptions.UserName = «log»;

    //sessionOptions.Password = «mypassword»;

    sessionOptions.PortNumber = «22»;

    sessionOptions.SshHostKeyFingerprint = «ssh-rsa 2048 010101010110101001012010»;

    sessionOptions.SshPrivateKeyPath = «С:1111.ppk»;

    session = Новый COMОбъект(«WinSCP.Session»); //Создаем объект Session

    //параметр необходимо использовать если пути регистрации DLL и исполняемого файла различны

    session.ExecutablePath = «C:Program Files (x86)WinSCPwinscp.exe»;

    // Подключаемся

    session.Open(sessionOptions);

    Ошибка:

    {Обработка.Обработка1.Форма.Форма.Форма(20)}: Ошибка при вызове метода контекста (Open): Произошла исключительная ситуация (WinSCPnet): Disconnected: No supported authentication methods available (server sent: publickey)

    Reply
  35. nytlenc

    (34) ferre, файл ключ с паролем?

    Reply
  36. nytlenc

    (34) ferre, если да то добавь sessionOptions.SshPrivateKeyPassphrase = «ТвойПарольНаКлюч»;

    Reply
  37. Dimka74

    Коллеги, подскажите как зарегистрировать WinSCP.dll, дело в том, что я в принципе такого файла найти не могу, нашел WinSCPnet.dll.

    Зарегистрировал библиотеку командой

    %WINDIR%Microsoft.NETFramework64v4.0.30319RegAsm.exe WinSCPnet.dll /codebase /tlb

    в ответ получил

    Типы зарегистрированы успешно

    Сборка экспортирована в «C:Windowssystem32WinSCPnet.tlb»; библиотека типов зарегистрирована успешно

    Пытаюсь соединиться по sftp, 1 ска выдает ошибку:

    {ОбщийМодуль.МойМодуль.Модуль(296)}: Ошибка при вызове конструктора (COMОбъект): -2147221164(0x80040154): Недопустимая строка с указанием класса

    Что не так сделано?

    Reply
  38. ram3

    (37) Dimka74,

    Коллеги, подскажите как зарегистрировать WinSCP.dll, дело в том, что я в принципе такого файла найти не могу, нашел WinSCPnet.dll.

    (37) Dimka74, в статье описание для версии 515, возможно сейчас что-то изменилось. Здесь есть вся информация по установке и регистрации http://winscp.net/eng/docs/library_install#registering

    Reply
  39. Dimka74

    (38) Спасибо за ответ, от туда информацию и черпал.

    Может быть теперь ошибка в коде 1с?

    Если изменилась библиотека, быть может теперь надо и код 1с править?

    Например раньше надо было так:

    sessionOptions = Новый COMОбъект(«WinSCP.SessionOptions»); //Создаем объект SessionOptions

    а сейчас надо так:

    sessionOptions = Новый COMОбъект(«WinSCPnet.SessionOptions»); //Создаем объект SessionOptions

    Хотя может быть мои знания устарели, и передача файла по SFTP в 1с возможна без лишних плясок — напрямую из платформы?

    Reply
  40. ram3

    (39) Dimka74,

    Может быть теперь ошибка в коде 1с?

    Если изменилась библиотека, быть может теперь надо и код 1с править?

    Я бы не стал называть это ошибкой, с версией 515 все работает. Если хотите использовать свежую версию, возможно придется адаптировать код. В заголовке статьи написано ПРИМЕР, это не готовое решение на все времена, и пожизненную поддержку никто не обещал.

    Хотя может быть мои знания устарели, и передача файла по SFTP в 1с возможна без лишних плясок — напрямую из платформы?

    На сколько я знаю, платформа 1С пока не поддерживает sFTP, только FTPS.

    Reply
  41. shved

    что значит ошибка:

    {ВнешняяОбработка.WinSCP.Форма.Форма.Форма(51)}: Ошибка при вызове метода контекста (Open): Произошла исключительная ситуация (WinSCPnet): Алгоритм обмена ключей diffie-hellman-group1-sha1 не был проверен!

    как проверить алгоритм?

    Reply
  42. shved



    при подключение оболочкой спрашивает про тоже самое, но тут можно нажать ДА и все ок.

    а как нажать Да через КОМ-соединение?

    Reply
  43. shved

    в оболочке нашел как сдвинуть свой алгоритм наверх.

    но как в ком… пока ищю

    добавил в парамтерах сессии

    bool GiveUpSecurityAndAcceptAnyTlsHostCertificate Give up security and accept any FTPS/WebDAVS server TLS/SSL certificate. To be used in exceptional situations only, when security is not required. When set, log files will include warning about insecure connection. To maintain security, use TlsHostCertificateFingerprint.

    но не помогло

    Reply
  44. shved

    версия последняя на седня 5.9.1. так и не победил.

    искать старые может. в них видимо такой проверки не было

    Reply
  45. shved

    победил!

    sessionOptions.AddRawSettings(«Cipher», «des,aes,chacha20,blowfish,3des,arcfour,WARN»);
    sessionOptions.AddRawSettings(«KEX», «dh-group1-sha1,ecdh,dh-gex-sha1,dh-group14-sha1,rsa,WARN»);
    
    Reply
  46. KokaDu

    Коллеги, после установки 1С платформы 8.3.9 и обновления WinSCP на 5.9.2 у меня просто «Неизвестная ошибка»

    {ВнешняяОбработка.ЗагрузкаФайлаСFTPСервера.Форма.Форма.Форма(92)}: Ошибка при вызове метода контекста (Open)

    session.Open(sessionOptions);

    по причине:

    Неизвестная ошибка

    Даже и не знаю куда копать. Может кто подскажет?

    Reply
  47. ram3

    (46) KokaDu, два варианта: либо качать старую версию WinSCP, либо смотреть документацию по новой версии и менять вызов метода .Open, видимо здесь «sessionOptions» что-то не соответствует новой версии.

    Уже были проблемы с новой версией выше в комментариях. Я с WinSCP уже давно не работаю, проверить к сожалению не могу…

    Reply
  48. KokaDu

    (47) ram3, перерыл документацию, ничего нового по «Open» не нашел.

    Проблему обошел тем, что создал bat-ник из самого WinSCP , который запускается из 1С.

    В любом случае спасибо.

    Reply
  49. Bujnovskij_Pavel

    Спасибо большое!! Очень помогли

    Reply
  50. Shooroopik111

    (48)

    (47) ram3, перерыл документацию, ничего нового по «Open» не нашел.

    Проблему обошел тем, что создал bat-ник из самого WinSCP , который запускается из 1С.

    В любом случае спасибо.

    Проблема ошибки OPEN встала очень остро.

    Переход на старую версию не помог. ВЫявил следующую закономерность: при простой регистрации компоненты через командную строку и работе на клиенте все ок.

    Как только регистрируем компоненту в службе компонентов чтоб работало на серваке- ловим ошибку OPEN. Может быть кто то победил ее?

    Reply
  51. KokaDu

    Сделайте батник по работе с WinSCP, пример во вложении.

    Reply
  52. ABudnikov

    (50) столкнулся с такой же проблемой. Вам удалось победить регистрацию WinSCP для работы на сервере?

    Reply
  53. KokaDu

    После регистрация WinSCP как 64 битного приложения проблема с OPEN остаётся.

    Предлагаю следующие варианты решения с использованием батника:

    Во вложении примеры с получением и отправки файла.

    У меня есть еще решение с использованием Putty, если будет интересно, тоже могу поделиться.

    Reply
  54. shved

    коллеги, у меня длл регается как

    %WINDIR%Microsoft.NETFramework64v4.0.30319
    egasm.exe WinSCPnet.dll /codebase /tlb:WinSCPnet.tlb

    сама длл тут https://winscp.net/download/WinSCP-5.9.4-Automation.zip

    далее

    sessionOptions = Новый COMОбъект(«WinSCP.SessionOptions»); //Создаем объект SessionOptions
    sessionOptions.HostName     = «192.168.0.1»;
    sessionOptions.UserName     = «порно»;
    sessionOptions.Password     = «секс»;
    sessionOptions.PortNumber     = 22;
    sessionOptions.SshHostKeyFingerprint  = «ssh-rsa 1024 7d:43:b7:43:05:30:01:3a:9f:e6:75:d8:29:e6:ca:fd»;
    
    sessionOptions.AddRawSettings(«Cipher», «des,aes,chacha20,blowfish,3des,arcfour,WARN»);
    sessionOptions.AddRawSettings(«KEX», «dh-group1-sha1,ecdh,dh-gex-sha1,dh-group14-sha1,rsa,WARN»);
    
    session = Новый COMОбъект(«WinSCP.Session»); //Создаем объект Session
    
    // Подключаемся
    session.Open(sessionOptions);
    

    Показать

    далее послать принять как обычно

    ПС вин2008р2 64. 1с8*64

    Reply
  55. ABudnikov

    (54) Спасибо. Заработало. Только я последовательно выполнил

    %WINDIR%Microsoft.NETFrameworkv4.0.30319RegAsm.exe WinSCPnet.dll /codebase /tlb:WinSCPnet32.tlb

    %WINDIR%Microsoft.NETFramework64v4.0.30319RegAsm.exe WinSCPnet.dll /codebase /tlb:WinSCPnet64.tlb

    на всякий случай чтоб в двух вариантах работало.

    И всё заработало.

    Reply
  56. denium

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

     //Задаем параметры подключения
    sessionOptions = Новый COMОбъект(«WinSCP.SessionOptions»); //Создаем объект SessionOptions
    sessionOptions.ParseUrl(«ftpes://User:Pasword@некий.сайт.ru»);
    sessionOptions.TlsHostCertificateFingerprint  =  «XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:04:XX:XX:XX:XX:XX:XX:XX»;
    session = Новый COMОбъект(«WinSCP.Session»); //Создаем объект Session
    //параметр необходимо использовать если пути регистрации DLL и исполняемого файла различны
    session.ExecutablePath = «C:Program FilesWinSCPwinscp.exe»;
    // Подключаемся
    session.Open(sessionOptions);

    Показать

    Reply
  57. Dach
    Reply
  58. spetrov77

    Хотел добавить, если вы устанавливаете FTPES соединение

    УРЛ = «ftpes://» + Логин + «:» + Пароль + «@» + АдресСервера;

    sessionOptions.ParseUrl(УРЛ);

    необходима версия WINSCP 5.9.2 и выше

    Reply
  59. Anastasia_Obrokova

    Очень интересно решение с использованием Putty, если можно — поделитесь, пожалуйста.

    Reply
  60. alex_gbi

    Как выяснилось WinSCP любит .NET framework 2.0 больше чем 4.5

    Если у вас появляется ошибка 0x80131700 то стоит установить 2.0.

    Возможно кому то помог.

    Reply
  61. sandybaev

    Добавлю к «как выяснилось» к посту выше

    скачав с их офф сайта winSCPnet.dll — регистрируете через RegAsm но согласно разрядности вашей ОС.

    т.е. для win64 это путь — C:WindowsMicrosoft.NETFramework64v4.0.30319

    или

    для win32 это — C:WindowsMicrosoft.NETFrameworkv4.0.30319

    да и если работаете в клиент серверном варианте, то, версия утилиты на сервере должна совпасть с вашей локальной установкой.

    Reply
  62. Shaldryn

    (55) походу из за того что сервер 1С 64 битный и оська 64 битная, спасибо, помогло

    Reply
  63. pomestnik

    Чтобы не париться с SshHostKeyFingerprint

    можно так сделать:

    fingerprint = session.ScanFingerprint(sessionOptions,»SHA-256″);

    sessionOptions.SshHostKeyFingerprint = fingerprint;

    Reply
  64. pinkz80

    Немного не в тему, но с FTPS тоже долго искал инфу, пришлось справку читать 🙂

    Сервер = Новый FTPСоединение(ИПFTP, 21,ЛогинFTP,ПарольFTP,,Истина,300,,УровеньИспользованияЗащищенногоСоединенияFTP.ИспользоватьЕслиВозможно);

    на удивление заработало. 8.3.11, в режиме совместимости 8.2.16

    Reply
  65. ram3

    (64) SFTP и FTPS — это разные вещи

    Reply
  66. user776571

    Мои 5 копеек:

    // Подключаемся

    session = Новый COMОбъект(«WinSCP.Session»); //Создаем объект Session

    session.open(sessionOptions);

    версия WinSCP 5.11.3

    Reply
  67. ram3

    (66) А в чем тут отличие?

    Reply
  68. user776571

    (67) в моих глазах ))), в исходном примере потерял )))

    Reply
  69. CratosX

    (12) на хабре написали в 2015, что исходники были потеряны

    Reply
  70. cool.vlad4

    (69) ты на дату моего поста посмотри

    Reply
  71. Bale

    Подскажите пожалуйста, я могу получить файлы (например *.txt) с sFTP, не выгружая в каталог на диске, а сразу в 1С?

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *