Cette source a pour but de montrer comment créer un fichier autoextractible contenant plusieurs fichiers.
Pour voir son fonctionnement :
1 - Ouvrer SaveData.sln
2 - Creer SaveData.exe
3 - Lancez le
Explication du programme de sauvegarde :
1 - Copie du fichier RestoreData.dat (qui est en fait l'exe du projet de restauration) dans le repertoire cible sous le nom donné par l'utilisateur
2 - Boucle qui parcours les fichiers du répertoire source
3 - Ecriture dans le fichier Xml de sortie (contient les infos de chaques fichiers nécéssaires à l'extraction)
4 - Ecriture de chaque fichier à la suite du fichier de sortie qui contient déjà RestoreData (40Ko ca va ;))
5 - Fin de la boucle
Note : Pour refaire RestoreData.dat, créez l'éxecutable du projet de restauration puis renommez le en .dat et enfin copiez le dans le répertoire de l'éxecutable de sauvegarde.
Explication du programme de restauration:
1 - Execution du fichier de Restauration créé précédemment
2 - Boucle qui parcours le fichier Xml et décrypte toutes ses infos
3 - Ecriture de chaque fichier à l'emplacement d'origine
4 - Fin de la boucle
Source très commenté.
Source / Exemple :
Option Strict On
Module ModSave
Friend PourCent As Integer = 0 'Avancement total
Friend PourCentInFile As Integer = 0 'Avancement du fichier
Friend CurrentPath As String = "" 'Fichier courant
Friend NewThread As Threading.Thread 'Déclaration du Thread
Friend BytesWrite As Long = 0 'Octets écrits
Friend Source, Destination, Nom As String 'Source, Destination et Nom
Friend Sub StartSave()
'Démarrage du Thread
NewThread = New Threading.Thread(AddressOf StartThread)
NewThread.Start()
End Sub
Private Sub StartThread()
'Procédure du démarrage du Thread
SaveDir()
End
End Sub
Public Sub SaveDir()
Try
'On initie les valeurs
PourCent = 0
PourCentInFile = 0
Dim CurrentFile As IO.FileStream 'Fichier courant qui va être lu
Dim CurrentFileInfo As IO.FileInfo 'Infos sur le fichier qui va être lu
Dim BytesStep As Integer = 1024 * 512 'Nombre d'octets à lire à la fois
Dim Bytes(BytesStep) As Byte 'Le tableau de bytes
Dim BytesRead As Integer 'Octets lus dans le flux
Dim PathFile As String = "" 'Chemin du fichier
Dim DirOfPathFile As String = "" 'Chemin du répertoire du fichier
'On créé une liste de tous les fichiers
Dim TblFiles() As String
TblFiles = IO.Directory.GetFiles(Source, "*.*", IO.SearchOption.AllDirectories)
'On créé le répertoire de la sauvegarde s'il n'existe pas
If IO.Directory.Exists(Destination & "\" & Nom) = False Then IO.Directory.CreateDirectory(Destination & "\" & Nom)
'On copie le projet Exe de restauration si le fichier cible n'exite pas
IO.File.Copy(Application.StartupPath & "\RestoreData.dat", Destination & "\" & Nom & "\" & Nom & ".exe", True)
'On ouvre un nouveau flux dans le fichier cible après l'Exe servant au déchiffrage
Dim FileCible As New IO.FileStream(Destination & "\" & Nom & "\" & Nom & ".exe", IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite, BytesStep)
'On met la position du flux à la fin des données du programme de restauration du fichier cible
Dim InfoFileRestore As New IO.FileInfo(Application.StartupPath & "\RestoreData.dat")
'Creation du début des données du fichier Xml contenant toutes les données nécéssaires au déchiffrage
Dim DataFileXml As String = ""
DataFileXml = "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "utf-8" & Chr(34) & "?>"
DataFileXml &= "<Structure>"
'On sauve tous les fichiers
For u As Integer = 0 To (TblFiles.Length - 1)
Try
CurrentPath = TblFiles(u) 'On change de fichier courant
CurrentFile = New IO.FileStream(TblFiles(u), IO.FileMode.OpenOrCreate, IO.FileAccess.Read, IO.FileShare.Read, BytesStep) 'On change de fichier de lecture, on donne les acces et on met le buffer sur 16 octets
CurrentFileInfo = New IO.FileInfo(TblFiles(u)) 'Info sur le fichier en lecture courant
PathFile = Replace(TblFiles(u), Source, "") 'On ne garde que le chemin qui se trouve dans le répertoire soure
If Microsoft.VisualBasic.Left(PathFile, 1) = "\" Then PathFile = Mid(PathFile, 2) 'On enlève le "\" du début
DirOfPathFile = Replace(CurrentFileInfo.DirectoryName, Source, "") 'On ne garde que le chemin qui se trouve dans le répertoire soure
If Microsoft.VisualBasic.Left(DirOfPathFile, 1) = "\" Then DirOfPathFile = Mid(DirOfPathFile, 2) 'On enlève le "\" du début
DataFileXml &= "<Fichier>" & "<Chemin>" & PathFile & "</Chemin>" & "<Debut>" & CStr(FileCible.Position) & "</Debut>" & "<Taille>" & CStr(CurrentFile.Length) & "</Taille>" & "<DirPath>" & DirOfPathFile & "</DirPath>" & "</Fichier>" 'Eriture des infos du fichier nécéssaires au déchiffrage dans le fichier Xml
For i As Long = 1 To (CurrentFile.Length) Step BytesStep 'On lit BytesStep à la fois
BytesRead = CurrentFile.Read(Bytes, 0, (BytesStep - 1)) 'On lit n octets et on range tout ca dans Bytes
FileCible.Write(Bytes, 0, BytesRead) 'On les ecrit dans le fichier de destination si le tabelau d'octets est different
BytesWrite = FileCible.Position 'Bytes écrits
If (CurrentFile.Length - 1) > 0 Then PourCentInFile = CInt(Math.Round(i / (CurrentFile.Length - 1) * 100)) 'Progression de l'écriture
Next i
CurrentFile.Close() 'On ferme le fichier de lecture pour passer au suivant
CurrentFile = Nothing 'CurrentFile vaut plus rien
If (TblFiles.Length - 1) > 0 Then PourCent = CInt(Math.Round(u / (TblFiles.Length - 1) * 100)) 'Avancement par Fichier
Catch ex As Exception
MsgBox("Erreur : " & vbCrLf & ex.Message, MsgBoxStyle.OkOnly Or MsgBoxStyle.Critical, "Erreur") 'Erreur!
End Try
Next u
'On ferme le fichier cible
FileCible.Close()
FileCible = Nothing
DataFileXml &= "</Structure>" 'On termine le fichier Xml
'On sauve les données Xml
Dim FileXml As New IO.StreamWriter(New IO.FileStream(Destination & "\" & Nom & "\" & Nom & ".xml", IO.FileMode.Create, IO.FileAccess.Write), System.Text.Encoding.UTF8)
FileXml.Write(DataFileXml)
'On ferme le fichier Xml
FileXml.Close()
Catch ex As Exception
MsgBox("Erreur : " & vbCrLf & ex.Message, MsgBoxStyle.OkOnly Or MsgBoxStyle.Critical, "Erreur")
End Try
End Sub
End Module
-------------------------------------------------------------------------------------------------------------------------------------
Option Strict On
Module ModRestore
Friend PourCent As Integer = 0 'Avancement total
Friend PourCentInFile As Integer = 0 'Avancement du fichier
Friend CurrentPath As String = "" 'Fichier courant en cours d'extraction
Friend NewThread As Threading.Thread 'Déclaration du thread
Friend BytesWrite As Long = 0 'Octets écrits
Friend Source As String 'Source (L'executable)
Friend PathCible As String 'Repertoire d'extraction
Friend Sub StartRestore()
'Démarrage du Thread
NewThread = New Threading.Thread(AddressOf StartThread)
NewThread.Start()
End Sub
Private Sub StartThread()
'Procédure du démarrage du Thread
Source = Application.ExecutablePath 'La source est evidemment l'Exe lui même d'où le terme "autoextractible"
RestoreDir()
End
End Sub
Private Sub RestoreDir()
Try
'On definit les variables
Dim FilePath, DirPath As String 'Chemin du fichier de destination
Dim FileLenght, FilePosition As Long 'Position dans le fichier .dat et longueur
Dim CurrentFile As IO.FileStream 'Flux du fichier de sortie
Dim BytesStep As Integer = 1024 * 512 'Nombre d'octets à lire à la fois
Dim Bytes(BytesStep) As Byte 'Le tableau de bytes
Dim BytesRead As Integer 'Octets lus dans le flux
Dim MaxLenght As Integer 'Longueur maximum d'oectets à lire
'On initie les valeurs
PourCent = 0
PourCentInFile = 0
If Microsoft.VisualBasic.Right(PathCible, 1) <> "\" Then PathCible &= "\" 'On rajoute "\" s'il n'existe pas
'On definit le fichier de sauvegarde xml
Dim DataFilePath As String = Mid(Source, 1, Source.Length - 3) & "xml"
'On ouvre le fichier xml qui contient les informations nécéssaires à la restauration
Dim XInfoFiles As New Xml.XmlDocument
XInfoFiles.Load(DataFilePath)
'On ouvre le fichier data avec les acces et un buffer de 16
Dim DataFile As New IO.FileStream(Source, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read, BytesStep)
'Parcours du fichier XMl et restauration des données
For u As Integer = 0 To (XInfoFiles.DocumentElement.ChildNodes.Count - 1)
Try
'Lecture des infos
FilePath = PathCible & XInfoFiles.DocumentElement.ChildNodes(u).ChildNodes(0).ChildNodes(0).Value
FilePosition = CLng(XInfoFiles.DocumentElement.ChildNodes(u).ChildNodes(1).ChildNodes(0).Value)
FileLenght = CLng(XInfoFiles.DocumentElement.ChildNodes(u).ChildNodes(2).ChildNodes(0).Value)
If XInfoFiles.DocumentElement.ChildNodes(u).ChildNodes(3).ChildNodes.Count > 0 Then DirPath = PathCible & (XInfoFiles.DocumentElement.ChildNodes(u).ChildNodes(3).ChildNodes(0).Value) Else DirPath = PathCible
If IO.Directory.Exists(DirPath) = False Then IO.Directory.CreateDirectory(DirPath) 'Si le dossier existe pas, on le créé
CurrentPath = FilePath 'Mise dans la variable du fichier courant en cours d'extraction
CurrentFile = New IO.FileStream(FilePath, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.Write, BytesStep) 'On ouvre le fichier où écrire les données avec les accès et toujours un buffer de 16 octets
DataFile.Position = FilePosition 'On va a la position du début du fichier
MaxLenght = BytesStep
For i As Long = 1 To (FileLenght) Step BytesStep 'n octet par n octet, on créé le fichier
If CurrentFile.Position + MaxLenght > FileLenght Then MaxLenght = CInt(FileLenght - CurrentFile.Position + 1)
BytesRead = DataFile.Read(Bytes, 0, (MaxLenght - 1)) 'On lit n octets dans le fichier autoextractible
CurrentFile.Write(Bytes, 0, BytesRead) 'Et on les écrits
BytesWrite = DataFile.Position 'Bytes écrits
If (FileLenght - 1) > 0 Then PourCentInFile = CInt(Math.Round(i / FileLenght * 100)) 'Progression de l'écriture
Next i
'On ferme le fichier écrit pour passer au suivant
CurrentFile.Close()
CurrentFile = Nothing
If (XInfoFiles.DocumentElement.ChildNodes.Count - 1) > 0 Then PourCent = CInt(Math.Round(u / (XInfoFiles.DocumentElement.ChildNodes.Count - 1) * 100)) 'Avancement par Fichier
Catch ex As Exception
MsgBox("Erreur : " & vbCrLf & ex.Message, MsgBoxStyle.OkOnly Or MsgBoxStyle.Critical, "Erreur") 'Erreur!
End Try
Next u
'On ferme le fichier data
DataFile.Close()
DataFile = Nothing
Catch ex As Exception
MsgBox("Erreur : " & vbCrLf & ex.Message, MsgBoxStyle.OkOnly Or MsgBoxStyle.Critical, "Erreur")
End Try
End Sub
End Module
Conclusion :
Cette source peut être largement améliorée :
Quelques idées :
1 - Algorithme de codage de HuffMan, utile pour réduire la taille du fichier
2 - Cryptage des données
3 - Mise à jour sans réécrire tout le fichier
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.