Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Rebonjour à tous!
Voilà un petit problème qui ne trouve malheureusement pas de solution pour l'instant:
- J'ai un fichier pdf sur mon disque dur
- Je dois le charger dans une datawindow, par exemple via un ole object.
- Je dois récupérer le blob qui se trouve dans l'ole object pour mettre le pdf en DB via un update blob.
Comment vous faites ça vous? Parce que moi... je nage... Je ne peux évidemment pas me dispenser de transiter par la DW, sinon j'aurais fait autrement... Et je me fiche de l'affichage (pour l'instant en tout cas) du pdf.
Toute idée ou piste est la bienvenue!
Merci!
Hors ligne
Bonjour,
Tu me parais avoir une approche extrêmement compliqué. Il suffit de lire le fichier PDF avec les fonctions de lecture classique de fichier pour le récupérer dans un blob : FileOpen, FileReadEx, FileClose.
Puis, tu sauvegardes le blob dans la base de données avec une requête embedded SQL.
Hors ligne
Salut,
je vais faire mon contrariant mais... pourquoi dois-tu absolument passer par une DW ?
Hors ligne
Salut,
on a fait ça sans OLE et sans DW, simplement en embeded SQL dans PB.
Il faut passer ton document PDF dans un BLOB (utilisation de fileopen(as_pathPDF,streammode!,Read!,LockRead!), FileReadEx(...) en boucle et FileClose(...)) puis faire un INSERT DB (sans le champs BLOB) et seulement après un UPDATEBLOB avec ton BLOB. L'insert DB se fait en 2 coups, impossible d'insérer un BLOB directement en DB.
Bons tests
Hors ligne
Shed a écrit:
Je ne peux évidemment pas me dispenser de transiter par la DW, sinon j'aurais fait autrement...
Et pour quelle raison, l'utilisation de UPDATEBLOB n'est pas possible en Embedded SQL dans ton cas ?
Hors ligne
Chez nous aussi on fait l'insert en deux fois, un INSERT pour un UPDATEBLOB
Je me souviens avoir essayé de jouer un peu avec les OLE dans les DW à l'époque et je n'avais pas trouvé ça très terrible.
Par exemple ouvrir le fichier depuis la DW avec une application et le modifier pour les renvoyer après dans la DB ne marche pas avec toutes les applications.
Si mes souvenirs sont bons j'avais essayé de charger le blob dans la datawindow sans succès.
Pour l'affichage l'ActiveX Adobe ne convenant pas à nos besoin j'en ai programmé un moi même en VB.net (à l'aide de librairies tierces)
Mais il serait intéressant de connaitre la raison profonde pour laquelle tu dois absolument passer par une DW
Hors ligne
Chers tous,
Je suis bien d'accord avec vous sur la façon idéale et même "normale" de procéder pour aller taper un blob en db. Mais comme je vous l'ai dit dans mon post initial, je dois passer par une dw. Si vous tenez tant à savoir pourquoi, je vais essayer de vous expliquer ça assez succinctement: Nous sommes dans une application client-serveur(eas)-db. Le client est en PB et n'a évidemment pas accès à la DB, et les composants serveur sont PB aussi. Le client est codé de façon ultra générique et la seule possibilité que nous avons à l'heure actuelle pour faire transiter des données du client vers la DB est d'utiliser la datawindow. Nous nous sommes contenté de cette seule possibilité pendant des années mais nous devons aujourd'hui faire un peu évoluer les choses et permettre l'upload de fichiers (ici on commence par le pdf). On pourrait aller recoder les strates abstraites du client, mais autant dire que cela risque de nous prendre énormément de temps d'implémenter un mécanisme complémentaire (sans risquer des dommages collatéraux aux fonctionnalités qui existe déjà). C'est donc pour cela qu'on se dirige plutôt vers l'amélioration de l'existant.
Actuellement, nous avons trouvé la solution suivante (attention, code à l'arrache):
integer bmpno, icount, li_FileNum string filepath, filename blob blb_tmp, blb_tmp2, blb_tmp3 long li_fileid // Coté client: GetFileOpenName ( "Please select file", filepath, filename, "PDF", "PDF files (*.PDF), *.*") dw1.object.ole_1.InsertFile (filepath) li_fileid = FileOpen (filepath, StreamMode!) FileReadex (li_fileid, blb_tmp) FileClose (li_fileid) dw1.object.filesize[1] = len(blb_tmp) // Coté serveur: blb_tmp2 = dw1.object.ole_1.objectdata blb_tmp3 = blobmid (blb_tmp2, 2544, dw1.object.filesize[1])
Notes:
- Les 2544 octets correspondent au header du wrapper ole pour un fichier pdf. Il va juste falloir trouver quelque chose de plus robuste pour déterminer la taille du header (mais ça fonctionne déjà bien ainsi)
- Le FileReadex n'est utilisé que pour obtenir la taille du fichier en octets. Je pense qu'il doit y avoir mieux comme méthode pour obtenir la taille sans passer par une variable ou on stocke le fichier.
- Je ne l'ai pas mis dans l'exemple, mais on fait évidemment un updtadeblob juste après.
Dernière modification par Shed (25-10-2013 09:23:17)
Hors ligne
Ce que tu pourrais faire:
Côté client tu encodes ton blob en base 64 comme ça tu peux le mettre dans ta DW dans un string et non plus un OLE.
Côté serveur tu décodés ta string base 64 et le tour est joué.
Tu as divers exemple de conversion blob / base 64 sur ce forum (surtout ne pas le faire en PB, utilise une dll C ou l'OLE MSXML sinon tu vas avoir de très mauvaises performances).
Ce n'est sûrement pas la solution idéale mais elle a le mérite d'être simple à mettre en oeuvre.
Hors ligne
Hummm... c'est pas con tiens... Par contre la taille du string sur une dw n'est pas limitée? Parce qu'un pdf de 10Mo, ça va faire une chiée de caractères ^^ :-D
Hors ligne
arf... si à 63999 caractères il me semble... je n'avais pas pensé à ça.
avec ton architecture (je n'ai jamais travaillé comme ça donc je n'en ai aucune idée) il est possible de faire des DW dynamiques ?
tu splittes ta chaine base 64 en tronçons de 63999 caractères et tu crées dynamiquement les columns dans ta DW et les lis dynamiquement sur le serveur.
Sinon il n'y a pas moyen de faire passer le fichier autrement sans tout bouleverser ? genre un petit webservice ? le faire passer avec un post HTTP ou le déposer sur un FTP ?
Hors ligne
Shed a écrit:
- Le FileReadex n'est utilisé que pour obtenir la taille du fichier en octets. Je pense qu'il doit y avoir mieux comme méthode pour obtenir la taille sans passer par une variable ou on stocke le fichier.
FileLength/FileLength64(filename) ?
Hors ligne
_francois_ a écrit:
arf... si à 63999 caractères il me semble... je n'avais pas pensé à ça.
avec ton architecture (je n'ai jamais travaillé comme ça donc je n'en ai aucune idée) il est possible de faire des DW dynamiques ?
tu splittes ta chaine base 64 en tronçons de 63999 caractères et tu crées dynamiquement les columns dans ta DW et les lis dynamiquement sur le serveur.
Ce qui voudrait dire que pour un fichier de 20Mo, je vais aller créer une centaine de colonnes dynamiquement... Ca tient la route ça? Et niveau perf? Puis y'a peut-être aussi une limitation sur le nombre de colonnes...
_francois_ a écrit:
Sinon il n'y a pas moyen de faire passer le fichier autrement sans tout bouleverser ? genre un petit webservice ? le faire passer avec un post HTTP ou le déposer sur un FTP ?
Si, j'ai pensé à l'envoyer par ftp... Mais ça me fait deux protocoles de communications, des ports à ouvrir, un serveur ftp à configurer... Bref, de la gestion système supplémentaire, sans que ça reste très propre en plus.
xlat a écrit:
FileLength/FileLength64(filename) ?
En effet :-)
Hors ligne
bon j'ai trouvé un truc
dans ta datawindow "normale" tu insères un objet OLE de type Acrobat Reader
puis dans le code coté client tu peux charger le PDF dans l'OLE
dw_2.object.ole_1.object.loadFile("f:\xxx.pdf")
Je ne garantie pas que tu le retrouveras de l'autre coté
Mais si on le retrouve bien sur le serveur soit tu arrives à récupérer le binaire directement
Soit il faudra faite un savefile (voir le vrai de la fonction) sur le même principe que le loadFile
en tout cas ça m’intéresse de voir si ça marche, ça pourra me donner des idées pour le futur
Hors ligne
Bonjour,
C'est bien compliqué tout ça. Il te suffit d'écrire un nouveau composant sur ton serveur EAS avec une méthode prenant un blob en argument et réalisant la sauvegarde dans la base de données.
Et de coder côté client :
Integer li_fileid Long ll_rc String ls_filepath, ls_filename, ls_properties[ ] blob lblb_blob connection conn n_blob ln_blob conn = create connection conn.driver = "jaguar" conn.location = "jaguar:9000" conn.application = "BLOB" conn.userID = "jagadmin" conn.password = "****" IF GetFileOpenName ( "Please select file", ls_filepath, ls_filename, "PDF", "PDF files (*.PDF), *.*") = 1 THEN li_fileid = FileOpen (ls_filepath, StreamMode!) FileReadex (li_fileid, lblb_blob) FileClose (li_fileid) ll_rc = conn.ConnectToServer() IF ll_rc <> 0 THEN MessageBox("Connexion échoué", ll_rc) RETURN END IF ll_rc = conn.CreateInstance( ln_blob , "BLOB/n_blob") IF ll_rc = 0 THEN ln_blob.uf_save(ls_filepath, lblb_blob) ELSE MessageBox("Création échoué", ll_rc) END IF END IF conn.DisconnectServer()
Hors ligne
buck, je sais comment effectuer une connexion au serveur et lui filer un blob. Mais comme je l'ai dit, je dois faire ça dans une application client lourde et abstraite qui possède un framework super restrictif. Je ne peux pas coder ce genre de chose, le framework de l'appli impose de passer par une DW pour passer des données au serveur. Et comme je l'ai déjà dit, je ne toucherai pas à ce framework.
Dernière modification par Shed (25-10-2013 13:22:24)
Hors ligne
_francois_ a écrit:
bon j'ai trouvé un truc
dans ta datawindow "normale" tu insères un objet OLE de type Acrobat Reader
puis dans le code coté client tu peux charger le PDF dans l'OLE
dw_2.object.ole_1.object.loadFile("f:\xxx.pdf")
Je ne garantie pas que tu le retrouveras de l'autre coté
Mais si on le retrouve bien sur le serveur soit tu arrives à récupérer le binaire directement
Soit il faudra faite un savefile (voir le vrai de la fonction) sur le même principe que le loadFile
en tout cas ça m’intéresse de voir si ça marche, ça pourra me donner des idées pour le futur
Charger le fichier, ça marche nickel. Le récupérer depuis l'OLE sur le serveur, c'est une autre paire de manche:
.objectdata = --> Ca marche pas
.savefile ---> Ca marche pas
La liste des functions de l'objet ne présente pas de sauvegarde possible (trouvée sur le net) et je n'ai pas accès aux propriétés de l'objet pour en extirper le blob.
... L'objet est bien dans l'OLE, mais je trouve pas comment le récupérer dans mon blob...
Dernière modification par Shed (25-10-2013 14:11:08)
Hors ligne
Côté serveur, peux-tu avoir accès à un répertoire (accessible aussi par les clients) ?
Si oui, tu pourrais :
- côté client : sélectionner le PDF local, faire une copie dans le répertoire accessible par le serveur, passer le chemin d'accès au PDF copié via ta DW
- côté serveur : récupérer le path dans la DW et procéder à la sauvegarde "normale"
C'est envisageable ça ?
Hors ligne
Oui ça marcherait mais non. Partager un dossier entre mes clients et mon serveur, c'est la porte ouverte des enfers
Au mieux, comme je l'ai déjà dit, j'ai pensé à l'envoi ftp. Mais c'est pas propre d'avoir deux protocoles de communication.
Hors ligne
Et programmer ton propre Ole Object / utiliser autre chose que Acrobat Reader pour avoir un save côté serveur ?
Est-ce que tu sais déterminer si le binaire arrive bien côté serveur ou non ?
Hors ligne
_francois_ a écrit:
Et programmer ton propre Ole Object / utiliser autre chose que Acrobat Reader pour avoir un save côté serveur ?
Sinon, sans rire, trouver des objets qui font des save, doit y en avoir, mais faut encore pouvoir charger un fichier pdf dedans...
_francois_ a écrit:
Est-ce que tu sais déterminer si le binaire arrive bien côté serveur ou non ?
A priori oui, ça passe juste par un getfullstate/setfullstate qui ne fait juste qu'envelopper la dw.
On a testé la méthode en passant par un string, c'est vraiment dommage d'être limité à 32ko par string car c'est ultrarapide.
Hors ligne
Shed a écrit:
_francois_ a écrit:
Et programmer ton propre Ole Object / utiliser autre chose que Acrobat Reader pour avoir un save côté serveur ?
Sinon, sans rire, trouver des objets qui font des save, doit y en avoir, mais faut encore pouvoir charger un fichier pdf dedans...
Mais non c'est super facile (la preuve j'en ai fait un en début d'année sans expérience dans le domaine ou en .net)
Il suffit d'avoir un VB.net (Express suffit)
Installer le Microsoft Interop Forms Toolkit
Et faire un nouveau projet "VB6 Interop UserControl"
Une fonction qui sauvegarde ton blob dans un byte() (pas besoin de conversion)
une fonction qui return le byte()
Bon après il faut déployer l'ActiveX chez le(s) client(s)
Sinon si tu trouves comment mettre un OLE non visual dans une datawindow il faut mettre une classe Msxml2.DOMDocument.6.0
Si jamais tu veux tenter le coup je veux bien essayer de te filer un coup de mail
Hors ligne