Archive avec lecture des fichiers dans l'ordre qu'on veut !

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Archive avec lecture des fichiers dans l'ordre qu'on veut !

Message par Thyphoon »

Voici un code que j'ai fait il y a quelques temps qui permet de faire une archive (nom compressé) avec un peu tout ce qu'on veut dedans.
image/son/mémoire/chaine de caractère/long etc...
l’intérêt est surtout qu'une fois l'archive ouverte vous n'êtes pas obligé de tout charger d'un coup et vous n'êtes pas obligé de charger les fichiers dans l'ordre.
je n'avais pas ajouté de compression car il y a des problèmes de compatibilité entre x64 et X86 dans le packer de PB, et aussi car la plus part des fichiers que je mettais dans l'archive était déjà compressé (jpg/mp3)

Bref il est loin d'être parfait mais peut être que ça sera utilise a quelqu'un et il ne doit pas être trop difficile a modifier pour rajouter ce que vous voulez dans l'archive.

L'idée est d'avoir un Quad en début de fichier qui contient l'adresse du catalogue
on ajoute tout ce qu'on veut a l'archive et au moment de clôturer ça écrit le catalogue. A l'ouverture de l'archive ça ne lit que le catalogue (ça prend pas de place) ensuite vous pouvez charger ce que vous voulez et quand vous voulez ...
:P
tout cela peut nettement être améliorer ... je ferais peut être des mise à jour ... :roll:

Code : Tout sélectionner

; Data types
Enumeration
  #ResFile
  #ResLong
  #ResString
EndEnumeration

; - Structure Ressource
Structure Ressource
  type.l  ; See Data types
  file.s  ; nom du fichier ou nom tout court
  size.q  ;Taille des données
  pack.l  ;0 pas compressé
  filepointer.q
EndStructure

Structure pack
  file.s  ;Nom du pack
  id.i    ;PB handle of the file
  List ressource.Ressource() ;list des données
EndStructure

;Create an empty archive 
Procedure CreateArchive(*pack.pack,file.s)
  *pack\file=file.s
  *pack\id=CreateFile(#PB_Any, *pack\file)
  If *pack\id
    WriteQuad(*pack\id,0); je reserve la place pour l'adresse du catalogue
  EndIf  
  
EndProcedure

;ajoute un fichier a l'archive
Procedure AddFileToArchive(*pack.pack,file.s)
  Define size.q,*mem,tmpId.i
  size.q=FileSize(file)
  If size>0
    *mem=AllocateMemory(size)
    tmpId.i=ReadFile(#PB_Any,file)
    If tmpId
      ReadData(tmpId,*mem,size)
      CloseFile(tmpId)
      ;Si on veut crypter ou compresser il faut faire ici
      If WriteData(*pack\id,*mem,size)>0
        AddElement(*pack\ressource())
        *pack\ressource()\type=#ResFile
        *pack\ressource()\file=file
        *pack\ressource()\size=size
        *pack\ressource()\pack=0
        FreeMemory(*mem)
        ProcedureReturn #True
      EndIf
    EndIf
  EndIf 
  ProcedureReturn #False
EndProcedure

;ajoute une chaine a l'archive
Procedure AddStringToArchive(*pack.pack,name.s,value.s)
  Define size.q
  size.q=StringByteLength(value,#PB_Unicode);+2
  ;Si on veut crypter ou compresser il faut faire ici
  If WriteString(*pack\id,value,#PB_Unicode)>0
    AddElement(*pack\ressource())
    *pack\ressource()\type=#ResString
    *pack\ressource()\file=name
    *pack\ressource()\size=size
    *pack\ressource()\pack=0
    ProcedureReturn #True
  EndIf 
  ProcedureReturn #False
EndProcedure

;ajoute un long a l'archive
Procedure AddLongToArchive(*pack.pack,name.s,value.l)
  Define size.q
  size.q=4
  ;Si on veut crypter ou compresser il faut faire ici
  If WriteLong(*pack\id,value)<>0
    AddElement(*pack\ressource())
    *pack\ressource()\type=#ResLong
    *pack\ressource()\file=name
    *pack\ressource()\size=size
    *pack\ressource()\pack=0
    ProcedureReturn #True
  EndIf 
  ProcedureReturn #False
EndProcedure

;ferme l'archive et ecrit le catalogue
Procedure CloseCreateArchive(*pack.pack)
  adrStartCatalog.q=Loc(*pack\id)      ; Je note l'adresse
  FileSeek(*pack\id, 0)           ; je retourne au debut du fichier
  WriteQuad(*pack\id,adrStartCatalog)  ; j'écrit l'adresse note avant (qui sera l'adresse du catalogue)
  Debug "debut de fichier "+Str(Loc(*pack\id))      ; Je note l'adresse debut de fichier
  FileSeek(*pack\id, adrStartCatalog)  ; je retourne a l'adresse 
  
  ; j'écris le catalogue
  WriteLong(*pack\id,ListSize(*pack\ressource()));d'abord le nombre de fichier
  ForEach *pack\ressource() ;puis pour chaque écriture
    WriteLong(*pack\id,*pack\ressource()\type)  ; le type de l'ecriture
    WriteQuad(*pack\id,*pack\ressource()\size)  ; la taille de ce qui est ecrit
    fileName.s=GetFilePart(*pack\ressource()\file)  ; l
    WriteStringN(*pack\id,fileName,#PB_Unicode) ; le nom
  Next
  CloseFile(*pack\id) ; et enfin je ferme le packacge
EndProcedure

;ouvre l'archive et lit le catalogue
Procedure ReadArchives(*pack.pack,file.s)
  *pack\file=file.s
  *pack\id=ReadFile(#PB_Any, file)
  If *pack\id
    ;Lit ou se trouve le catalogue  
    adrStartCatalog.q=ReadQuad(*pack\id)
    adrStartFile.q=Loc(*pack\id) ;adresse du debut des fichiers
    FileSeek(*pack\id, adrStartCatalog) ; on se deplace pour trouver le catalogue
    ;je lis le catalogue
    n=ReadLong(*pack\id)
    For z=0 To n-1
      AddElement(*pack\ressource())
      *pack\ressource()\type=ReadLong(*pack\id)
      *pack\ressource()\size=ReadQuad(*pack\id)
      ;lenght.l=ReadLong(id)
      ;*pack\ressource()\file=ReadString(id)
      ;WriteLong(id,StringByteLength(fileName,#PB_Unicode))
      *pack\ressource()\file=ReadString(*pack\id,#PB_Unicode)
      Debug *pack\ressource()\file
    Next
    
    ForEach *pack\ressource()
      *pack\ressource()\filepointer=adrStartFile
      adrStartFile=adrStartFile+*pack\ressource()\size
    Next
    
  EndIf
  ProcedureReturn *pack\id
EndProcedure

;pour lire des données et les stocker en mémoire quelques soit le type
Procedure ReadMemFromArchives(*pack.pack,adrStartFile.q,size.q)
  *mem=AllocateMemory(size)
  FileSeek(*pack\id, adrStartFile)
  ReadData(*pack\id,*mem,size)
  ProcedureReturn *mem
EndProcedure

;pour capturer une image a partir de l'archive
Procedure CatchImageFromArchives(*pack.pack,imageId.i,file.s)
  Protected result.i
  fileclose=#False ; part défaut on ne ferme pas le fichier apres la lecture
  If IsFile(*pack\id)=#False ; mais si le fichier est déjà fermé alors on l'ouvre et on le refermera apres
    *pack\id=ReadFile(#PB_Any,*pack\file)
    fileclose=#True
  EndIf
  ForEach *pack\ressource()
    If *pack\ressource()\file=file
      Debug"trouvé la"
      *mem=ReadMemFromArchives(*pack,*pack\ressource()\filepointer,*pack\ressource()\size)
      result.i=CatchImage(imageId,*mem,*pack\ressource()\size)
      FreeMemory(*mem)  ;plus besoin de la mémoire on la libère
    EndIf
  Next
  If fileclose=#True
    CloseFile(*pack\id)
  EndIf
  Debug result
EndProcedure

Procedure.S CatchStringFromArchives(*pack.pack,name.s)
  fileclose=#False ; part défaut on ne ferme pas le fichier apres la lecture
  If IsFile(*pack\id)=#False ; mais si le fichier est déjà fermé alors on l'ouvre et on le refermera apres
    *pack\id=ReadFile(#PB_Any,*pack\file)
    fileclose=#True
  EndIf
  ForEach *pack\ressource()
    If *pack\ressource()\file=name
      Debug"trouvé"
      *mem=ReadMemFromArchives(*pack,*pack\ressource()\filepointer,*pack\ressource()\size)
      value.s=PeekS(*mem,-1,#PB_Unicode)
      FreeMemory(*mem)
    EndIf
  Next
  If fileclose=#True
    CloseFile(*pack\id)
  EndIf
  ProcedureReturn value
EndProcedure

Procedure.l CatchLongFromArchives(*pack.pack,name.s)
  fileclose=#False ; part défaut on ne ferme pas le fichier apres la lecture
  If IsFile(*pack\id)=#False ; mais si le fichier est déjà fermé alors on l'ouvre et on le refermera apres
    *pack\id=ReadFile(#PB_Any,*pack\file)
    fileclose=#True
  EndIf
  ForEach *pack\ressource()
    If *pack\ressource()\file=name
      Debug"trouvé"
      FileSeek(*pack\id, *pack\ressource()\filepointer)
      value.l=ReadLong(*pack\id)
    EndIf
  Next
  If fileclose=#True
    CloseFile(*pack\id)
  EndIf
  ProcedureReturn value
EndProcedure


Procedure CloseReadArchive(*pack.pack)
  CloseFile(*pack\id)
EndProcedure

;-TEST
UsePNGImageDecoder()
pack.pack
CreateArchive(@pack,"test.pk")
AddStringToArchive(@pack,"clavier","azerty")
AddFileToArchive(@pack,"04-00.png")
AddLongToArchive(@pack,"chiffre",123456)
AddFileToArchive(@pack,"05-00.png")
AddStringToArchive(@pack,"script","blablablablablabla"+#LFCR$+"coucou")
AddFileToArchive(@pack,"06-00.png")
CloseCreateArchive(@pack)
test.pack
Debug "____"
ReadArchives(test,"test.pk")
CatchImageFromArchives(test,1,"05-00.png")
Debug SaveImage(1,"testimage.bmp") ;juste pour tester si l'image a bien fonctionné
CloseReadArchive(test.pack)
Debug CatchLongFromArchives(test,"chiffre")
Debug CatchStringFromArchives(test,"script")
Debug CatchStringFromArchives(test,"clavier")
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par graph100 »

C'est rigolo :mrgreen: j'avais pris le même type d'architecture pour une archive de mon projet SCMangwa (mais que avec des images)
On fait tous la même chose !

As-tu/veux-tu pensé à comment faire si on veux modifier l'archive par la suite ?
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par Thyphoon »

graph100 a écrit :C'est rigolo :mrgreen: j'avais pris le même type d'architecture pour une archive de mon projet SCMangwa (mais que avec des images)
On fait tous la même chose !
Oui je crois qu'on rencontre tous les même problèmes ! :mrgreen:
graph100 a écrit : As-tu/veux-tu pensé à comment faire si on veux modifier l'archive par la suite ?
J'ai une idée si on veut rajouter des données a l'archive, ça écrase le catalogue en bout de fichier et rajoute le fichier ou les données puis réécrit le catalogue.
Apres pour la suppression de donnée j'ai aussi une idée avec un genre de deframenteur mais ça sera peut être très lent. Mais comme j'en ai pas encore eu besoin je ne l'ai pas (encore) développé ! :P
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par Anonyme2 »

Thyphoon a écrit : je n'avais pas ajouté de compression car il y a des problèmes de compatibilité entre x64 et X86 dans le packer de PB, et aussi car la plus part des fichiers que je mettais dans l'archive était déjà compressé (jpg/mp3)
Salut Thyphoon,
tu peut utiliser Zlib, il y a un code simple sur le forum anglais
http://www.purebasic.fr/english/viewtop ... 13&t=39728

Je l'utilise (avec une petite modif propre à mon code) et c'est OK en x_64 et x_86.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par Thyphoon »

Denis a écrit :
Thyphoon a écrit : je n'avais pas ajouté de compression car il y a des problèmes de compatibilité entre x64 et X86 dans le packer de PB, et aussi car la plus part des fichiers que je mettais dans l'archive était déjà compressé (jpg/mp3)
Salut Thyphoon,
tu peut utiliser Zlib, il y a un code simple sur le forum anglais
http://www.purebasic.fr/english/viewtop ... 13&t=39728

Je l'utilise (avec une petite modif propre à mon code) et c'est OK en x_64 et x_86.
super Denis ! merci beaucoup
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par graph100 »

Thyphoon a écrit :
graph100 a écrit : As-tu/veux-tu pensé à comment faire si on veux modifier l'archive par la suite ?
J'ai une idée si on veut rajouter des données a l'archive, ça écrase le catalogue en bout de fichier et rajoute le fichier ou les données puis réécrit le catalogue.
Apres pour la suppression de donnée j'ai aussi une idée avec un genre de deframenteur mais ça sera peut être très lent. Mais comme j'en ai pas encore eu besoin je ne l'ai pas (encore) développé ! :P
Moi j'avais pensé faire un catalogue de l'espace vide, en fait comme une base de donnée, c'est d'ailleurs dommage que les bases de donnée soient lentes dans les écritures d'un grand nombre de mémoire (je crois), et mettre les prochains fichiers dans les espaces vides. Mais j'ai peur de me retrouver avec un gruyère trop rapidement :? Et comme je traite des fichiers archives en moyenne de 2Go, c'est pas super pour reconstruire le fichier sans fragmentations !

Faudrait implémenter un système de fichier spécial pour les archives (un genre de disque virtuel à taille variable) :mrgreen: :mrgreen:
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par Thyphoon »

graph100 a écrit : Faudrait implémenter un système de fichier spécial pour les archives (un genre de disque virtuel à taille variable) :mrgreen: :mrgreen:
:D mon rêve !! :o)
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Archive avec lecture des fichiers dans l'ordre qu'on veu

Message par graph100 »

je pense que ça serais super utile pour des archives de grandes tailles ! du genre > 100Mo
Au dessous, la taille des infos nécessaires au maintien du système de fichier deviens non négligeable, je pense ;'(

Je me demande, si on ne pourrais pas utiliser un système avec un hachage numérique de l'id de chaque dossiers / fichiers, de manière à ne stocker qu'une seule fois le nom de chaque objet
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Répondre