Page 1 sur 1

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

Publié : sam. 18/juin/2011 22:25
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")

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

Publié : sam. 18/juin/2011 22:33
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 ?

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

Publié : sam. 18/juin/2011 22:48
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

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

Publié : dim. 19/juin/2011 7:42
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.

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

Publié : dim. 19/juin/2011 8:21
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

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

Publié : dim. 19/juin/2011 18:15
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:

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

Publié : dim. 19/juin/2011 19:19
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)

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

Publié : lun. 20/juin/2011 16:50
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