PureBasic

Forums PureBasic
Nous sommes le Dim 18/Nov/2018 19:43

Heures au format UTC + 1 heure




Poster un nouveau sujet Répondre au sujet  [ 9 messages ] 
Auteur Message
 Sujet du message: Lire un fichier Excel (.xlsx)
MessagePosté: Mer 10/Mai/2017 17:07 
Hors ligne

Inscription: Jeu 07/Juin/2007 22:54
Messages: 177
Bonjour,

Suite à une demande de "moulinette" pour faire des recherches croisés entre plusieurs fichier Excel qui m'a été fait, j'en ai profité pour faire les choses à peut près proprement.
Si ça peut servire à quelqu'un...
Code:
EnableExplicit
DeclareModule Excel
  Declare Open(File$) ; Returns the new generated number if the file was opened successfully and zero if there was an error
  Declare Close(File) ; Returns nonzero if the operation was successful or zero if it failed.
  Declare CountSheets(File) ; Returns amount of sheets in the workbook, zero if can't count.
  Declare.s GetSheetName(File,Sheet=1) ; Returns sheet name of the #sheet, "" if it failed.
  Declare CountRow(File,Sheet=0) ; Returns amount of row in the #sheet, zero if can't count.
  Declare CountCol(File,Sheet=0) ; Returns amount of col in the #sheet, zero if can't count.
  Declare LoadSheet(File,Sheet) ; Returns nonzero if the operation was successful or zero if it failed.
  Declare.s ReadCell(File,Row,Col,Sheet=0) ; Returns cell value, " " if empty, "" if it failed.
EndDeclareModule

Module Excel
  UseZipPacker()
  Structure file
    File.i
    SharedString.i
    Sheet.i
    WorkBook.i
  EndStructure
 
  Procedure Open(File$)
    *pack.file = AllocateMemory(SizeOf(file))
    If Not GetExtensionPart(File$) = "xlsx" : ProcedureReturn #False : EndIf
    *Pack\File = OpenPack(#PB_Any,File$)
    If *pack\File
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File))
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\_rels")
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\docProps")
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\xl")
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\xl\_rels")
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\xl\printerSettings")
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\xl\theme")
      CreateDirectory(GetTemporaryDirectory()+Str(*Pack\File)+"\xl\worksheets")
      ExaminePack(*Pack\File)
      While NextPackEntry(*Pack\File)
        UncompressPackFile(*Pack\File,GetTemporaryDirectory()+Str(*Pack\File)+"\"+PackEntryName(*pack\File))
      Wend
      ClosePack(*Pack\File)
      *pack\WorkBook = LoadXML(#PB_Any,GetTemporaryDirectory()+Str(*Pack\File)+"\xl\workbook.xml")
      If Not XMLStatus(*pack\WorkBook) = #PB_XML_Success : ProcedureReturn #False : EndIf
      *pack\SharedString = LoadXML(#PB_Any,GetTemporaryDirectory()+Str(*Pack\File)+"\xl\sharedStrings.xml")
      If Not XMLStatus(*pack\SharedString) = #PB_XML_Success : ProcedureReturn #False : EndIf
      ProcedureReturn *Pack
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure
 
  Procedure Close(*File.file)
    If Not *File : ProcedureReturn #False : EndIf
    If IsXML(*File\SharedString) : FreeXML(*File\SharedString) : EndIf
    If IsXML(*File\Sheet) : FreeXML(*File\Sheet) : EndIf
    If IsXML(*File\WorkBook) : FreeXML(*File\WorkBook) : EndIf
    If DeleteDirectory(GetTemporaryDirectory()+Str(*File\File),"*.*",#PB_FileSystem_Recursive)
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure
 
  Procedure CountSheets(*File.file)
    If Not *File : ProcedureReturn #False : EndIf
    Protected node
    node = MainXMLNode(*file\WorkBook)
    node = ChildXMLNode(node,4)
    ProcedureReturn XMLChildCount(node)
  EndProcedure
 
  Procedure.s GetSheetName(*File.file,Sheet=1)
    If Not *File : ProcedureReturn  "" : EndIf
    Protected node
    node = MainXMLNode(*File\WorkBook)
    node = ChildXMLNode(node,4)
    While Not GetXMLNodeName(node) = "sheets"
      node = NextXMLNode(node)
      If node = 0 : ProcedureReturn "" : EndIf
    Wend
    node = ChildXMLNode(node,Sheet)
    If node
      ProcedureReturn GetXMLAttribute(node,"name")
    Else
      ProcedureReturn ""
    EndIf
  EndProcedure
 
  Procedure CountRow(*File.file,Sheet=0) ; If sheet is set to 0, the current (or 1st if not current) Sheet will be read.
    If Not *File : ProcedureReturn #False : EndIf
    Protected node, Row$
    If Sheet = 0
      If IsXML(*File\Sheet) = 0
        If Not LoadSheet(*File,1) : ProcedureReturn #False : EndIf
      EndIf
    Else
      If Not LoadSheet(*File,Sheet) : ProcedureReturn #False : EndIf
    EndIf
    node = MainXMLNode(*File\Sheet)
    node = ChildXMLNode(node)
    While GetXMLNodeName(node) <> "dimension"
      node = NextXMLNode(node)
    Wend
    row$ = ReverseString(((ReverseString(StringField(GetXMLAttribute(node,"ref"),2,":")))))
    Repeat
      If Asc(row$) < 48 Or Asc(row$) > 57
        row$ = RemoveString(row$,Chr(Asc(row$)))
      Else
        Break
      EndIf
    ForEver   
    ProcedureReturn Val(Row$)
  EndProcedure
 
  Procedure CountCol(*File.File,Sheet=0) ; If sheet is set to 0, the current (or 1st if not current) Sheet will be read.
    If Not *File : ProcedureReturn #False : EndIf
    Protected node, col, size
    If Sheet = 0
      If IsXML(*File\Sheet) = 0
        If Not LoadSheet(*File,1) : ProcedureReturn #False : EndIf
      EndIf
    Else
      If Not LoadSheet(*File,Sheet) : ProcedureReturn #False : EndIf
    EndIf
    node = MainXMLNode(*File\Sheet)
    node = ChildXMLNode(node)
    While GetXMLNodeName(node) <> "dimension"
      node = NextXMLNode(node)
    Wend
    size = Len(StringField(GetXMLAttribute(node,"ref"),2,":")) - Len(Str(Val((ReverseString(StringField(GetXMLAttribute(node,"ref"),2,":"))))))
    If size = 1
      ProcedureReturn Asc(Left(StringField(GetXMLAttribute(node,"ref"),2,":"),1))-64
    ElseIf size = 2
      ProcedureReturn (Asc(Left(StringField(GetXMLAttribute(node,"ref"),2,":"),1))-64)*26 + Asc(Left(Right(StringField(GetXMLAttribute(node,"ref"),2,":"),Len(StringField(GetXMLAttribute(node,"ref"),2,":"))-1),1))-64
    EndIf
  EndProcedure
 
  Procedure LoadSheet(*File.file,Sheet)
    If Not *File : ProcedureReturn #False : EndIf
    If IsXML(*File\Sheet) : FreeXML(*File\Sheet) : EndIf
    *File\Sheet = LoadXML(#PB_Any,GetTemporaryDirectory()+Str(*File\File)+"\xl\worksheets\sheet"+Sheet+".xml")
    If XMLStatus(*File\Sheet) = #PB_XML_Success
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure
 
  Procedure.s ReadCell(*File.file,Row,Col,Sheet=0) ; If sheet is set to 0, the current (or 1st if not current) Sheet will be read.
    If Not *File : ProcedureReturn "" : EndIf
    Protected node, node2
    If Sheet = 0
      If IsXML(*File\Sheet) = 0
        If Not LoadSheet(*File,1) : ProcedureReturn "" : EndIf
      EndIf
    Else
      If Not LoadSheet(*File,Sheet) : ProcedureReturn "" : EndIf
    EndIf
    node = MainXMLNode(*File\Sheet)
    node2 = MainXMLNode(*File\SharedString)
    node = ChildXMLNode(node)
    While Not GetXMLNodeName(node) = "sheetData"
      node = NextXMLNode(node)
    Wend
    node = ChildXMLNode(node)
    While  Not Val(GetXMLAttribute(node,"r")) = row
      node = NextXMLNode(node)
      If node = 0 : ProcedureReturn " " : EndIf
    Wend
    If ChildXMLNode(node,col)
      node = ChildXMLNode(node,col)
    Else
      ProcedureReturn " "
    EndIf
    If GetXMLAttribute(node,"t") = "s"
      If ChildXMLNode(node)
        node = ChildXMLNode(node)
      Else
        ProcedureReturn " "
      EndIf
      node2 = ChildXMLNode(node2,Val(GetXMLNodeText(node))+1)
      If node2
        node2 = ChildXMLNode(node2)
        ProcedureReturn GetXMLNodeText(node2)
      Else
        ProcedureReturn ""
      EndIf
    ElseIf GetXMLAttribute(node,"t") = ""
      If ChildXMLNode(node)
        node = ChildXMLNode(node)
        ProcedureReturn GetXMLNodeText(node)
      Else
        ProcedureReturn " "
      EndIf
    ElseIf GetXMLAttribute(node,"t") = "e"
      If ChildXMLNode(node)
        node = ChildXMLNode(node)
        While Not GetXMLNodeName(node) = "v"
          node = NextXMLNode(node)
          If node = 0 : ProcedureReturn "" : EndIf
        Wend
        ProcedureReturn GetXMLNodeText(node)
      Else
        ProcedureReturn " "
      EndIf
    EndIf
     
  EndProcedure
 
EndModule

;=================================================Example of use=================================================
; Define xml, row, loop
; xml = Excel::Open(OpenFileRequester("",GetCurrentDirectory(),"Excel | *.xlsx",0))
; Debug Excel::GetSheetName(xml)
; row = Excel::CountRow(xml)
; Debug Excel::CountCol(xml)
; For loop = 1 To row
;   Debug Excel::ReadCell(xml,loop,1)
;   Debug Excel::ReadCell(xml,loop,2)
;   Debug Excel::ReadCell(xml,loop,7)
; Next
; Excel::Close(xml)
;================================================================================================================


C'est trés basique et ne fonctionne qu'avec des fichier Excel simple, mais c'est tout ce dont j'avais besoin.

Edit : certaines valeurs de cellules sont par fois dans le "sheet.xml" et rajout de la lecture du résultat des formules.

Edit : MAJ, il y avais un petit but sur la fonction CountRow


Dernière édition par boby le Jeu 24/Aoû/2017 17:29, édité 3 fois.

Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Jeu 11/Mai/2017 6:14 
Hors ligne

Inscription: Sam 08/Fév/2014 15:19
Messages: 1417
Excellent, merci.

On oublie souvent effectivement que le format XLSX est juste un lot de fichiers XML et texte, le tout zippé.
(Un xlsx s'ouvre très bien avec 7zip)

Comme PB gère le format zip et les nœuds XML on peut facilement extraire des données des fichiers xlsx
(plus facilement que l'ancien format xls)

:wink:


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Jeu 11/Mai/2017 12:37 
Hors ligne
Avatar de l’utilisateur

Inscription: Sam 23/Sep/2006 18:32
Messages: 6559
Localisation: Isere
Ouaih depuis l'abandon du format propriétaire XLS qui obligeait à passer soit par un moteur, soit par COMATE pour le lire avec PB
XLSX simplifie beaucoup la vie, et encore plus quand un copain le code pour vous :lol:
Ca pourra m'etre surement utile, car au boulot, ils savent pas prononcer une phrase sans qu'elle contienne le mot EXCEL dedans :?
Merci beaucoup BOBY du partage et soit le bienvenu (surtout pour ce genre de trucs utilitaires :mrgreen:), car je ne crois pas te l'avoir souhaité auparavant 8)

_________________
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Sam 02/Juin/2018 20:06 
Hors ligne
Avatar de l’utilisateur

Inscription: Jeu 14/Oct/2004 19:48
Messages: 1111
Très utile ! :D

_________________
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 5.45LTS - 32 bits


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Jeu 07/Juin/2018 1:22 
Hors ligne
Avatar de l’utilisateur

Inscription: Sam 26/Nov/2011 13:04
Messages: 444
Bonsoir à tous
Bizarre mais chez moi ça ne marche pas, voici le message d'erreur qui s'affiche puis fermeture du programme.
    Le fichier #XML n'est pas initialisé

_________________
Win7 (x86) 32 bits Pb 5.62


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Jeu 07/Juin/2018 8:09 
Hors ligne

Inscription: Sam 08/Fév/2014 15:19
Messages: 1417
omega a écrit:
Bonsoir à tous
Bizarre mais chez moi ça ne marche pas, voici le message d'erreur qui s'affiche puis fermeture du programme.
    Le fichier #XML n'est pas initialisé
Message étonnant, car il n'y a pas de constante #XML dans l'exemple donné par boby

As-tu ?
- Créé un fichier xlsx simple (xlsx = Fichier provenant d'Excel 2007 ou +)
- Copié/collé tout le code de bobby
- Désactivé l'exemple (partie entre ;=====)
- Copié strictement le message d'erreur ?

:wink:


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Ven 08/Juin/2018 17:43 
Hors ligne
Avatar de l’utilisateur

Inscription: Sam 26/Nov/2011 13:04
Messages: 444
Je reprends le message tel qu'il est affiché:

[17 :37 :25]
[17 :38 :59] Attente du démarrage du programme...
[17 :38 :59] Type d'exécutable: Windows - x86 (32bit, Unicode)
[17 :38 :59] Exécutable démarré.
[17 :39 :06] [ERREUR] testExcel1.pb (Ligne: 43)
[17 :39 :06] [ERREUR] Le #XML spécifié n'est pas initialisé.


et en ligne 43:
Code:
If Not XMLStatus(*pack\SharedString) = #PB_XML_Success : ProcedureReturn #False : EndIf

_________________
Win7 (x86) 32 bits Pb 5.62


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Mar 26/Juin/2018 17:13 
Hors ligne

Inscription: Jeu 07/Juin/2007 22:54
Messages: 177
Un XLSX est un fichier compressé contenant plusieurs XML, pas besoin de constante, c'est l'ouverture du XML "sharedStrings.xml" qui déconne dans ton cas.

test tu l'exemple avec un vrai fichier xlsx créé par excel ? ce fichier est-il lisible par excel ?
Si oui, ça dit quoi si tu colle
Code:
      If Not XMLStatus(*pack\WorkBook) = #PB_XML_Success : ProcedureReturn #False : EndIf
      Debug FileSize(GetTemporaryDirectory()+Str(*Pack\File)+"\xl\sharedStrings.xml")
      *pack\SharedString = LoadXML(#PB_Any,GetTemporaryDirectory()+Str(*Pack\File)+"\xl\sharedStrings.xml")
?


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: Lire un fichier Excel (.xlsx)
MessagePosté: Mer 27/Juin/2018 17:06 
Hors ligne
Avatar de l’utilisateur

Inscription: Jeu 14/Oct/2004 19:48
Messages: 1111
Rien à voir avec la discussion en cours, mais...
Code:
ElseIf GetXMLAttribute(node,"t") = "e" or GetXMLAttribute(node,"t") = "str"


Cette ligne à compléter pour prendre en compte ce cas là. 8)

_________________
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 5.45LTS - 32 bits


Haut
 Profil  
Répondre en citant le message  
Afficher les messages postés depuis:  Trier par  
Poster un nouveau sujet Répondre au sujet  [ 9 messages ] 

Heures au format UTC + 1 heure


Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 4 invités


Vous ne pouvez pas poster de nouveaux sujets
Vous ne pouvez pas répondre aux sujets
Vous ne pouvez pas éditer vos messages
Vous ne pouvez pas supprimer vos messages

Rechercher:
Aller à:  

 


Powered by phpBB © 2008 phpBB Group | Traduction par: phpBB-fr.com
subSilver+ theme by Canver Software, sponsor Sanal Modifiye