- Работа с FTP сервером с помощью %Net.FtpSession
- Простой способ выгрузки данных в формат xls
- Несколько полезных советов
Работа с FTP сервером.
Вебсервисы? Не, не слышали.
Третьего дня нашей компании довелось организовывать потоковую синхронизацию данных с производственным комплексом «Хэ». IT отдел заказчика настаивал на использовании FTP сервера, другие способы обмена яростно отвергались.
Нам понадобятся:
s ftp = ##class(%Net.FtpSession).%New() – класс для работы с FTP ftp.Timeout = время в миллисекундах – таймаута пакета ftp.Connect(хост, логин, пароль, порт) – коннект к FTP ftp.SetDirectory(директория) – путь к директории на FTP (относительно корневой) ftp.List(маска файла, ссылка на поток по значению) – вернёт список файлов, соответствующих маске, на ФТП в поток ftp.Binary() – бинарный режим передачи данных ftp.Retrieve(файл, .GlobalStream) – загрузка фала в поток ftp.Delete(файл) – удаление файла ftp.Append(имяфайла, поток) - дописать данные из потока в файл с именем ftp.Logout() – закрытие FTP коннекта
ClassMethod FTPGetFiles(ftp, fileName) As %Status { s ftp = ##class(%Net.FtpSession).%New() s ftp.Timeout = 2000 s host = "11.111.11.111" s port = 2021 s user = "myth/user" s pass = "userspass" if ftp.Connect(host, user, pass, port) { d ftp.SetDirectory("/TestDir") // Маска файла s fileName = "????????t??????vK*.xml" // Работа с файлами по маске в указанной папке d ..ParserDir(ftp, fileName) s fileName = "????????a??????yK*.xml" d ..ParserDir(ftp, fileName) } q ftp.Logout() } /// Загрузка в поток файлов, удовлетворяющих маске ClassMethod ParserDir(ftp, fileName) As %Status { s file = "" s x = 1 s file(x) = "" // Список файлов из папки в поток d ftp.List(fileName, .stream) q:'$IsObject(stream) while 'stream.AtEnd { // Чтение по одному символу из потока s file = stream.ReadLine(1, .sc, .eol) if ( file = $C(10) ) { // Формирование массива дескрипторов файла s x = x + 1 s file(x) = "" } else { // Формирование дескриптора файла s file(x) = file(x) _ file } if $$$ISERR(sc) { w "ERROR" q } } // Переключение в бинарный режим d ftp.Binary() // Получение дескриптора следующего файла s key = $ORDER(file(""),1) while ( key '= "" ) { // Имя файла s fName = $E(file(key), 40, *) if ( $L(fName) > 0 ) { #dim GlobalStream As %GlobalBinaryStream; // Дописываем данные из потока в файл с именем fName. В нашем случае из-за настроек виндового FTP и писем в CP1251 необходима трансформация кодировки d ftp.Retrieve($zcvt($zcvt(fName,"I","CP1251"),"O","CP1251"),.GlobalStream) #dim status As %String; // Поиск вхождения буквы в имени файла if ( $F(fName,"s") > 0 ) { s status = ..Parser(GlobalStream, "Product", "Shipment", parser) } elseif ( $F(fName,"d") > 0 ) { s status = ..Parser(GlobalStream, "Product", "Disposal" ,parser) } if ( status ) { d ftp.Delete(fName) } } s key = $order(file(key),1) } q ftp.Logout() }
/// Экспорт файлов на FTP сервер ClassMethod RunExport() As %Status { s ftp = ##class(%Net.FtpSession).%New() s ftp.Timeout = 2000 s host = "11.111.11.111" s port = 2021 s user = "myth/user" s pass = "userspass" if ftp.Connect(host, user, pass, port) { d ftp.Binary() // Получение файлов по маске в папке в порядке сортировки s st = ##class(%SQL.Statement).%New() d st.%PrepareClassQuery("%File","FileSet") s rs = st.%Execute("/usr/cachesys201221/csp/sm/export_xml","*.xml","Size,Name") while rs.%Next() { // Удаляем файл с сервера, если такой уже есть d ftp.Delete(rs.%GetData(6)) // Загружаем файл в поток s stream = ##class(%FileBinaryStream).%New() // 1 - Полный путь до файла на нашем локальном сервере s stream.Filename = rs.%GetData(1) // Если файл УСПЕШНО дописан на сервер - перемещаем его в директорию "done" if ( ftp.Append(rs.%GetData(6),stream) = $$$OK ) { d ##class(%File).Rename(rs.%GetData(1), ##class(%File).GetDirectory(rs.%GetData(1)) _ "done/" _ rs.%GetData(6)) } k stream } } d ftp.Logout() k ftp q $$$OK }
Выгрузка данных в формат xlsx.
Ничто так не радует, как горе у соседа.
Хорошо помню, как утром, по приходу в офис, мне улыбался коллега и не без доли злорадствия рапортовал о выходе новой версии Mozilla Firefox. А все потому, что задача экспорта данных в excel в наших программных продуктах была разрешена с помощью браузерного плагина, который использовал написанную на visual-C библиотеку. После смены политики безопасности приложений FireFox, мне предстояло при каждой смене версии, в лучшем случае, скачивать новую SDK и пересобирать DLL-ку (и плагин в целом), в худшем – переписывать сишный код для DLL-ки и JS парсер страницы). Про необходимость обновления плагина у пользователей и вспоминать не хочется.
Однако третьего дня и на нашей улице перевернулся грузовик с печеньем в виде простого способа экспорта в формат Excel, коим хочу поделиться с Вами:
- Берём (формируем) html таблицу с данными
- Сохраняем таблицу в текстовый файл, меняем расширение на xls
- Открываем файл, не забываем жмакнуть «да» на табличке с предупреждением и … вуаля! Эксель прекрасно распознал нашу таблицу. При необходимости ячейкам можно передавать css стили и указывать формат данных.
#server(TestProject.MakeExcelFile($("#table_to_excel").html(), "PriceList"))# ClassMethod MakeExcelFile(Data As %String, FileName As %String) As %Status { s FileName = "/tkf/reports/" _ FileName _ "_Excel.xls" s stream = ##class(%Library.FileCharacterStream).%New() s FP = $$GetFilename^%apiCSP(FileName) if ( $L(Data) = 22 ) { d stream.CopyFrom(Data) } else { d stream.Write(Data) } d stream.SetAttribute("Content-Length",stream.Size) d stream.SetAttribute("ContentType","application/excel") d stream.SetAttribute("Charset","UTF8") d stream.SetAttribute("ContentDisposition","attachment; filename=" _ $p(FileName,"/",4)) d stream.LinkToFile(FP) d stream.SaveStream() s oid = stream.%Oid() &js<window.location="#url(%25CSP.StreamServer.cls?STREAMOID=#(..Encrypt(oid))#)#";> q $$$OK }
Ячейке, к примеру, можно задать размер шрифта — <td style=”font-size:18px”>Анна Антонова</td>
, а можно указать числовой тип формата:
<style>.toText{ mso-number-format:\"\@\"; } </style> <td class=”toText”>Анна Антонова</td>
Полезные советы
Сокращения
Наверняка не все знают, что в COS существуют сокращенные версии операторов, вроде этих:
Set = s
Do = d
Write = w
Kill = k
Quit = q
…
Сокращения в большинстве случаев отражены в документации примерно так:
Типизация
COS — язык без строгой типизации, но иногда полезно или даже необходимо заранее провести типизацию, для этого и был создана конструкция #dim
Пример:
$CLASSNAME в SQL
Редкий, но вполне реальный случай – при построении запроса необходимо вывести имя класса (Аналог $CLASSNAME в SQL), для этих целей можно использовать скрытое поле, которое присуще всем классам — x__classname.
Пример:
Есть 2 класса A и B, которые наследуются от общего предка Letters Extends %Persistent. Включим в выборку поле x__classname.
Версия Cache — Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2012.2.1 (Build 705U) Wed Oct 24 2012 14:32:01 EDT.
ссылка на оригинал статьи http://habrahabr.ru/post/177609/
Добавить комментарий