programme python backup gratuit

Un programme Python de backup gratuit

  • Dernière modification de la publication :29 juin 2024
  • Temps de lecture :7 min de lecture
  • Commentaires de la publication :1 commentaire

Loading

Voici un programme Python de backup entièrement gratuit. J’en avais royalement marre de télécharger des programmes qui ne faisaient pas bien leur job, alors je m’y suis collé.

Un programme Python de backup: cahier des charges

Ce que je voulais:

  • Une interface graphique épurée
  • Pas de milliers d’options qui ne servent finalement à rien
  • Une sauvegarde incrémentielle (ne sauvegarde que les nouveaux fichiers)
  • Une sauvegarde des répertoires à sauvegarder et de la destination
  • Une lecture automatique des répertoires à sauvegarder dès le lancement du programme
  • La possibilité de supprimer un dossier si on ne veut plus l’inclure dans la sauvegarde
  • Une barre de progression, parce que bon! Il ne faut pas exagéré non plus… 🙂

Voici donc l’interface graphique:

programme en python de backup entièrement gratuit

Personnellement, je n’ai ps besoin de plus…

Les programmes de backup

J’ai essayé au fil des années plusieurs logiciels gratuits. Et bien qu’ils fussent faciles à utiliser pendant un certain temps, ils plantaient après.

Le dernier en date est Fbackup 9. J’en étais content jusqu’à ce que, d’un coup, il ne fasse plus les sauvegardes correctement. Il mettait toujours un message d’erreur comme quoi le chemin gnagna n’existait pas… Insupportable! C’en était trop! Il me fallait réagir! Je n’allais tout de même pas me laisser faire par une machine… non mais!

Le programme Python de backup que je vous propose

J’ai jeté mon dévolu sur Tkinter pour l’interface graphique. C’est tout de même plus simple que Qt par exemple. Et en plus, c’est inclus dans les distribution Python.

J’ai aussi opté pour la POO. J’aime bien… 🙂

Alors, plutôt que de longs discours (que personne ne lit de toute façon), voici le programme:

# -*- coding: utf-8 -*-
"""
Created on Sat Jun 29 15:47:22 2024

@author: Stéphane Pasquet
"""

import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import shutil
import os
import json

class BackupApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Programme de Backup")

        self.source_paths = []
        self.destination_path = tk.StringVar()

        self.create_widgets()
        self.load_paths()

    def create_widgets(self):
        tk.Label(self.root, text="Source:").grid(row=0, column=0, padx=10, pady=10)
        self.source_listbox = tk.Listbox(self.root, selectmode=tk.MULTIPLE, height=10, width=50)
        self.source_listbox.grid(row=0, column=1, rowspan=2, padx=10, pady=10)
        
        tk.Button(self.root, text="Ajouter Dossier", command=self.browse_source).grid(row=0, column=2, padx=10, pady=10)
        tk.Button(self.root, text="Supprimer Dossier", command=self.remove_selected_sources).grid(row=1, column=2, padx=10, pady=10)

        tk.Label(self.root, text="Destination:").grid(row=2, column=0, padx=10, pady=10)
        tk.Entry(self.root, textvariable=self.destination_path).grid(row=2, column=1, padx=10, pady=10)
        tk.Button(self.root, text="Parcourir", command=self.browse_destination).grid(row=2, column=2, padx=10, pady=10)

        tk.Button(self.root, text="Démarrer Backup", command=self.start_backup).grid(row=3, column=1, padx=10, pady=10)

        self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate")
        self.progress.grid(row=4, column=0, columnspan=3, padx=10, pady=10)

    def browse_source(self):
        sources = filedialog.askdirectory(mustexist=True)
        if sources:
            self.source_paths.append(sources)
            self.source_listbox.insert(tk.END, sources)
            self.save_paths()

    def browse_destination(self):
        destination = filedialog.askdirectory(mustexist=True)
        if destination:
            self.destination_path.set(destination)
            self.save_paths()

    def remove_selected_sources(self):
        selected_indices = self.source_listbox.curselection()
        selected_paths = [self.source_listbox.get(i) for i in selected_indices]
        for path in selected_paths:
            self.source_paths.remove(path)
        for i in selected_indices[::-1]:
            self.source_listbox.delete(i)
        self.save_paths()

    def start_backup(self):
        destination = self.destination_path.get()

        if not self.source_paths or not destination:
            messagebox.showerror("Erreur", "Veuillez sélectionner les répertoires source et destination.")
            return

        total_files = sum([len(files) for source in self.source_paths for _, _, files in os.walk(source)])
        self.progress["maximum"] = total_files
        self.progress["value"] = 0

        try:
            for source in self.source_paths:
                self.incremental_backup(source, destination)
            messagebox.showinfo("Succès", "Sauvegarde incrémentielle terminée avec succès.")
        except Exception as e:
            messagebox.showerror("Erreur", f"Une erreur est survenue: {e}")

    def incremental_backup(self, source, destination):
        for root, dirs, files in os.walk(source):
            relative_path = os.path.relpath(root, source)
            dest_dir = os.path.join(destination, os.path.basename(source), relative_path)
            if not os.path.exists(dest_dir):
                os.makedirs(dest_dir)
            for file in files:
                source_file = os.path.join(root, file)
                dest_file = os.path.join(dest_dir, file)
                if not os.path.exists(dest_file) or os.path.getmtime(source_file) > os.path.getmtime(dest_file):
                    shutil.copy2(source_file, dest_file)
                self.progress["value"] += 1
                self.root.update_idletasks()

    def save_paths(self):
        data = {
            "source_paths": self.source_paths,
            "destination_path": self.destination_path.get()
        }
        with open("paths.json", "w") as file:
            json.dump(data, file)

    def load_paths(self):
        if os.path.exists("paths.json"):
            with open("paths.json", "r") as file:
                data = json.load(file)
                self.source_paths = data.get("source_paths", [])
                self.destination_path.set(data.get("destination_path", ""))
                for path in self.source_paths:
                    self.source_listbox.insert(tk.END, path)

if __name__ == "__main__":
    root = tk.Tk()
    app = BackupApp(root)
    root.mainloop()

J’ai été très agréablement surpris par la rapidité à laquelle il a fait sa première sauvegarde, bien que plutôt costaude! Et les sauvegardes ultérieures, n’en parlons pas!

Vraiment, j’aime beaucoup ce programme, alors je le partage avec vous. Qu’en pensez-vous ?

0 0 votes
Évaluation de l'article
S’abonner
Notification pour
guest
1 Commentaire
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Philippe Rackette

Cela fonctionne bien sous MacOS, merci pour ce programme !