Datei-Backup optimieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Ich bin es leid, immer die Dateien für mein Backup, das mittlerweile mehrere DVDs umfasst, manuell auf die DVDs zu verteilen, um den Platz möglichst effektiv zu nutzen. Ich möchte deshalb ein Python-Script dafür erstellen. Dabei stellen sich mir 2 Probleme:
1. Alle Möglichkeiten zu berechnen, um mehrere Hundert Dateien auf 3 bis 4 DVDs zu verteilen, dürfte kaum möglich sein (schon 3^1000 ist nicht mehr zu bewältigen). Gibt es für so etwas bekannte Algorithmen?
2. Gibt es ein Command-Line-Tool oder ein über die Command-Line zu steuerndes GUI-Programm zum Brennen von DVDs unter Windows? Mir sind zwar mkisofs und cdrecord von Linux bekannt; da ich aber unter Windows arbeite, müsste ich diese dann wieder über cyqwin oder mingw laufen lassen, was ich ungern tuen würde.
Danke
HWK
Panke
User
Beiträge: 185
Registriert: Sonntag 18. März 2007, 19:26

Du könntest die Dateien rar'en und dabei mit -v die Dateigröße der einzelnen Rarteile angeben oder du speicherst (Größe / Pfad) in einer Liste (whatever) und suchst dir so die Dateien raus, dass du möglichst nah an 4,4GB kommst. Das dürfte mit einigen Hundert Dateien zu machen sein.

Apropos: Gib mal 3**1000 in den Interpreter ein. Einige Hundert!?
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Ich möchte möglichst kein Archiv speichern. Die Performance, aus einem 4,5 GByte großen Archiv eine Datei wiederzuladen, dürfte wohl relativ schlecht sein. Was ist, wenn das Archiv beschädigt ist? Möglicherweise sind dann alle Dateien nicht mehr zu lesen. Auch das Erstellen des Archivs selbst dürfte schon einige Zeit benötigen.
Mehrere Hundert bezog sich auf die Anzahl der zu speichernden Dateien. Dass 3^1000, d.h. die Zahl der Möglichkeiten, um 1000 Dateien auf 3 DVDs zu verteilen, nicht mehr zu bewältigen ist, also wesentlich größer als einige Hundert ist, sagte ich ja bereits selbst.
Trotzdem Danke für den Vorschlag.
MfG
HWK
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

zu 2.: Die beiden Windows-Brennprogramme burnatonce und InfraRecorder bringen bereits als .exe kompilierte Versionen dieser Tools mit, die du so benutzen können solltest. Vielleicht hilft dir das ja bereits.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Panke hat geschrieben:Du könntest die Dateien rar'en
Hallo Panke!

Wir haben lange Zeit RAR für Datensicherungen eingesetzt. Ich möchte jedem davon dringendst abraten. RAR braucht im Schnitt sieben (7) bis zehn (10) mal länger für die gleiche Datenmenge als ZIP. Schlimm wird es dann, wenn die Server am nächsten Vormittag immer noch beim Komprimieren der Sicherungen sind.

Wir haben darauf hin ein paar Tests gemacht und RAR, ZIP, BZIP2 und GZIP miteinander verglichen. GZIP arbeitet am Schnellsten und komprimiert dabei genügend gut. RAR und BZIP2 komprimieren ein bischen besser, brauchen aber dafür **viel mehr** Zeit. Dieses "bischen Besser" ist den Zeitaufwand nicht Wert.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Panke
User
Beiträge: 185
Registriert: Sonntag 18. März 2007, 19:26

Splittet mir gzip die Volumens automatisch? Oder muss ich da vorher ein Tar-Script schreiben?
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@YOGi: Danke für die Tips. Es scheinen aber beides Programme zu sein, die Windows-Oberflächen für die bekannten Linux-cdrtools erzeugen, so dass ich wieder cygwin verwenden muss. Wie gesagt möchte ich dies aber möglichst nicht.
@Gerold: Hälst Du es denn für sinnvoll, Pankes Vorschlag mit einem Deiner bevorzugten Komprimierer umzusetzen? Kann man mit GZIP z.B. ein riesiges Archiv auf mehrere DVDs verteilen?
Wie sieht es dann mit meinen o.g. Bedenken aus: Kann ich aus einem beschädigten Archiv noch einzelne Dateien restaurieren? Braucht das Zurückladen einzelner Dateien nicht sehr viel Zeit und Festplattenspeicher? Das Komprimieren an sich wäre für mich nebensächlich, da die meisten Dateien schon komprimiert sind.
MfG
HWK
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Panke hat geschrieben:Splittet mir gzip die Volumens automatisch? Oder muss ich da vorher ein Tar-Script schreiben?
Hallo Panke!

GZIP ist ein reines Kompressionsprogramm. Eine Datei oder ein Datenstream kann damit komprimiert werden. Es ist also nicht dafür geeignet, mehrere Dateien zu komprimieren. Dafür ist TAR vorgesehen. TAR komprimiert von sich aus die Daten mit GZIP, wenn man den Parameter "-z" verwendet.

TAR komprimiert aber erst nach dem Splitten. Deshalb verwende ich für so etwas lieber das Programm DAR http://dar.linux.free.fr/

DAR komprimiert zuerst mit GZIP und splittet erst danach. DAR ist so oder so ein Geheimtipp.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

HWK hat geschrieben:Ich möchte möglichst kein Archiv speichern. Die Performance, aus einem 4,5 GByte großen Archiv eine Datei wiederzuladen, dürfte wohl relativ schlecht sein.
Kommt auf das Archiv an. Bei ZIP ist es kein Problem gezielt auf eine Datei zuzugreifen.
Was ist, wenn das Archiv beschädigt ist? Möglicherweise sind dann alle Dateien nicht mehr zu lesen.
Das kommt auch wieder auf das Archiv an.

Ich benutze `tar.bz2` und sichere die Datenträger mit dvdisaster ab. Wenn man öfter auf einzelne Dateien aus der Sicherungskopie zugreifen muss, ist `tar.bz2` natürlich langsamer als ein ZIP-Archiv oder die Dateien direkt auf den Datenträger zu sichern. Das ist aber auch nicht das Szenario gegen dass ich mich absichern möchte. Mir geht's weniger um Einzeldateien, sondern mehr um kaputte Platten. Die zwei bis dreimal im Jahr, die ich gerne einzelne Dateien wiederhaben möchte, kann ich auch ein wenig warten.
Auch das Erstellen des Archivs selbst dürfte schon einige Zeit benötigen.
Das kommt, wie Gerold schon schrieb, auf die Komprimierung an. Der "deflate"-Algorithmus, der bei ZIP-Archiven und von `gzip` benutzt wird, ist recht schnell. Da stehen die Chancen gut, dass bei einem aktuellen Rechner die Rechenzeit kleiner, oder zumindest nicht wesentlich höher ist, als die Zeit, die auf die Platte gewartet werden muss.

Falls das immer noch nicht schnell genug ist, gibt's noch lzop. Angeblich das schnellste (De)Komprimierungsprogramm, wobei die Kompressionsrate nur ein wenig schlechter als beim "deflate"-Algorithmus ist.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

HWK hat geschrieben:@Gerold: Hälst Du es denn für sinnvoll, Pankes Vorschlag mit einem Deiner bevorzugten Komprimierer umzusetzen?
Hallo HWK!

Leider sind meine Vorschläge keine Lösung für dein Problem. Ich bin mir sicher, dass es für dein Problem fix und fertige Algorithmen gib.

Ich persönlich, würde mir die Suche danach aber gar nicht erst antun. Wenn du in einer Liste alle Dateinamen mit deren Größen hälst und diese nach Größe (absteigend) sortierst, dann kannst du diese Liste der Reihe nach abarbeiten. Das schließt zwar nicht aus, dass auf einer CD mehr und auf der anderen weniger drauf ist, aber du sparst dir dadurch das Durchrechnen aller Möglichkeiten.

Vielleicht so:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

from pprint import pprint

MAX_SIZE = 400000


def main():
    filelist = [
        [1000, "C:\\ordner1\\dateix.txt"],
        [51000, "C:\\ordner1\\dateiy.txt"],
        [100, "C:\\ordner1\\dateiu.txt"],
        [370000, "C:\\ordner1\\datei1.txt"],
        [770000, "C:\\ordner1\\i_am_to_large.txt"],
        [156000, "C:\\ordner1\\datei2.txt"],
        [61800, "C:\\ordner1\\datei3.txt"],
        [70000, "C:\\ordner1\\datei4.txt"],
        [175451, "C:\\ordner1\\datei5.txt"],
        [15783, "C:\\ordner1\\datei6.txt"],
    ]
    filelist.sort(reverse = True)
    
    destlist = []
    to_large = []
    for source_size, source_filename in filelist:
        if source_size > MAX_SIZE:
            to_large.append(source_filename)
            continue
        for index, (dest_size, dest_items) in enumerate(destlist):
            if (dest_size + source_size) <= MAX_SIZE:
                destlist[index][0] = dest_size + source_size
                dest_items.append(source_filename)
                break
        else:
            destlist.append([source_size, [source_filename]])
    
    pprint(destlist)
    pprint(to_large)


if __name__ == "__main__":
    main()

Code: Alles auswählen

[[386883,
  ['C:\\ordner1\\datei1.txt',
   'C:\\ordner1\\datei6.txt',
   'C:\\ordner1\\dateix.txt',
   'C:\\ordner1\\dateiu.txt']],
 [393251,
  ['C:\\ordner1\\datei5.txt',
   'C:\\ordner1\\datei2.txt',
   'C:\\ordner1\\datei3.txt']],
 [121000, ['C:\\ordner1\\datei4.txt', 'C:\\ordner1\\dateiy.txt']]]
['C:\\ordner1\\i_am_to_large.txt']
mfg
Gerold
:-)
Zuletzt geändert von gerold am Sonntag 8. Juli 2007, 11:47, insgesamt 2-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@BlackJack: dvdisaster ist ein guter Tip. Der zusätzliche Speicherbedarf von ca. 15% ist aber natürlich ziemlich heftig.
Noch eine Frage zum Verständnis: Wenn ich aus einem ZIP-Archiv eine einzelne Datei zurückladen will, muss dann erst das gesamte Verzeichnis von der DVD geladen werden?
Eine weitere rein informative Frage: Ist es notwendig oder zumindest sinnvoll, nach dem Brennen des Backups den Inhalt der DVD mit dem Original zu vergleichen, was ja die Backup-Zeit verdoppelt?
MfG
HWK
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

HWK hat geschrieben:Ist es notwendig oder zumindest sinnvoll, nach dem Brennen des Backups den Inhalt der DVD mit dem Original zu vergleichen, was ja die Backup-Zeit verdoppelt?
Hallo HWK!

Ich empfinde das Brennen auf DVDs als Glücksspiel. Ein geringer Datenverlust ist bei einem Video nicht merkbar. Aber in einer wichtigen Datendatei ist eine 0 statt einer 1 eine Katastrophe. So ungeduldig kann ich gar nicht sein, dass ich die Daten der gebrannten DVD nach dem Brennen nicht vergleiche. Komisch ist nur, dass es noch nie einen Fehler auf DVD gab, seit ich die Daten verifiziere. Aber Murphy ist überall. :roll:

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

@HWK: Auf Dateien in einer ZIP-Datei kann man direkt zugreifen. Im ZIP ist ein Inhaltsverzeichnis mit den Dateinamen und dem Offset innerhalb des Archivs gespeichert.

@gerold: Direkt nach dem brennen von DVDs habe ich auch noch nie einen Fehler gehabt, ausser das Brennprogramm hat schon gemeckert. Bei Rohlingen wo die Brenner-Firmware wohl nicht die idealen Einstellungen kannte, fing der Datenverlust aber schon mal nach ein paar Tagen an und wurde dann immer schlimmer.

Ich benutze jetzt immer die gleiche Rohlingsmarke und teste die Sicherungskopien zwei Tage nach dem brennen noch einmal. Dabei ist bis jetzt noch kein Fehler aufgetreten. Aber Du erwähntest Murphy ja schon.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

HWK hat geschrieben:@YOGi: Danke für die Tips. Es scheinen aber beides Programme zu sein, die Windows-Oberflächen für die bekannten Linux-cdrtools erzeugen, so dass ich wieder cygwin verwenden muss. Wie gesagt möchte ich dies aber möglichst nicht.
Bei mir sind das Kommandozeilen-Tools, die sich möglicherweise der mitgelieferten cygwin1.dll bedienen, aber das war's auch schon. Das ist unabhängig und über `subprocess` sicher problemlos benutzbar.


Zu den Archiven: RAR gefällt mir ganz und gar nicht, weil nur der Algorithmus zur Dekompression offen gelegt ist, der zur Kompression aber nicht. So einem Format werde ich daher keine Daten anvertrauen - schon gar nicht wichtige Backups oder Archive, die über viele Jahre wichtige Daten beherbergen sollen.

7-Zip (.7z) möchte ich noch nennen. Es hat eine sehr hohe Kompressionsrate, ist aber wie Bzip2 dann auch länger dabei.

Über letzteres meine ich zudem mal gelesen zu haben, dass die entpackte Datengröße aus dem Archiv selbst nicht abgeleitet werden kann. In dem Zusammenhang sind wohl auch mal "Archivbomben" für Virenscanner aufgetaucht, die nur wenige Kilo- oder Megabyte große Bzip2-Archive waren, sich aber auf mehrere Gigabyte entpackten.

Zum Thema Anfälligkeit von Archiven sei auch das Schlagwort "Solid (Archive)" genannt. Dazu aus der Wikipedia-Seite zu RAR:
Durch die Technik der progressiven bzw. Solid-Archivierung (Solid Mode bzw. Solid Archiving Technique) werden die ausgewählten Dateien nicht einzeln, sondern alle zusammen komprimiert. Dieses Verfahren findet sein Vorbild in komprimierten Tarballs.

Der Vorteil besteht darin, dass Redundanzen zwischen mehreren Dateien auch eliminiert werden können, was bei vielen kleineren gleichartigen Dateien den größten Effekt entfaltet. Außerdem brauchen so weniger formatspezifische Informationen gespeichert zu werden. Der Nachteil besteht in der Fehleranfälligkeit des gepackten Archivs, da es als Ganzes intakt sein muss, um einzelne Dateien zu extrahieren. Um diesen Nachteil etwas auszugleichen kann ein sogenannter Recovery Record mitabgespeichert werden, mit dem fehlerhafte RAR-Archive gegebenenfalls in begrenztem Umfang repariert werden können.
Ein Blick in die englische Wikipedia zu den gängigen Formaten ist ebenfalls zu empfehlen, weil dort oft mehr und bessere Information vorliegt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@Gerold: Danke für Dein Beispiel. Ich tendiere jetzt aber zu einer anderen Lösung. Meine zu sichernden Dateien befinden sich in mehreren Ordnern. Um nicht völliges Chaos auf den Backup-Medien zu erhalten, wäre es sowieso schön, möglichst einen kompletten Ordner auf das Medium zu brennen. Ich muss dann also nur noch die Ordner auf die DVDs verteilen. Das sind aber nicht so viele, dass ich nicht alle Möglichkeiten durchprobieren könnte. Der verschenkte Platz wird dadurch aber natürlich größer.
MfG
HWK

EDIT: So kann man sich täuschen: Es handelte sich dann doch um 91 Ordner. Somit waren trotz verschiedener Optimierungsversuche natürlich nicht alle Varianten zu berechnen. Ich habe dann doch Deine ja mittlerweile noch verbesserte Version implementiert und siehe da:
Auf 4 DVDs verteilt werden bei den ersten 3 DVDs nicht einmal 0,5 MByte verschenkt. Das ist doch wohl eine gute Ausbeute.
Ein bisschen habe ich Deinen Code allerdings geändert, weil mich das enumerate gestört hat:

Code: Alles auswählen

def divide(dir_list):
    '''Verzeichnisse auf mehrere DVDs verteilen.'''
    dir_list.sort(reverse=True)
    dest_list = []
    to_large = []
    for source_size, source_filename in dir_list:
        if source_size > MAXSIZE:
            to_large.append(source_filename)
            continue
        for dest_size, dest_items in dest_list:
            if (dest_size[0] + source_size) <= MAXSIZE:
                dest_size[0] += source_size
                dest_items.append(source_filename)
                break
        else:
            dest_list.append([[source_size], [source_filename]])
    return dest_list, to_large
Somit nochmals vielen Dank Gerold.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

So, das ist jetzt mein weitgehend fertiges Backup-Programm. Zum Brennen habe ich letztendlich Nero verwendet. Dies liegt ja vielen Brennern bei und kann mit nerocmd über die Kommandozeile gesteuert werden.

Code: Alles auswählen

#!/usr/local/bin/python
# -*- coding: cp1252 -*-
# File: Backup.py

'''Script zum optimierten Backup auf mehrere Medien.'''

import os


DIRFILE = 'Dirs.txt'
MAXSIZE = 4700000000
NEROCMD = 'c:\\programme\\nero\\"nero 7"\\Core\\nerocmd.exe --write '\
          '--drivename d --real --speed 04 --iso Backup.%03i --dvd '\
          '--detect_non_empty_disc --enable_abort --underrun_prot '\
          '--create_iso_fs --recursive --disable_eject --verify "%s"'
          #' --force_erase_disc'


def dirsize(name):
    '''Größe eines Verzeichnisses bestimmen.'''
    if not os.path.exists(name):
        return -1
    if os.path.isfile(name):
        return os.path.getsize(name)
    size = 0
    for path, dirs, files in os.walk(name):
        for dir_ in dirs:
            size += os.path.getsize(os.path.join(path, dir_))
        for file_ in files:
            size += os.path.getsize(os.path.join(path, file_))
    return size


def make_dir_list():
    '''Liste der Verzeichnisse und deren Größe erstellen.'''
    dir_list = []
    try:
        infile = file(DIRFILE, 'r')
        try:
            for name in infile:
                name = name.strip()
                if name.endswith(' S'):
                    name = name[:-2]
                    if os.path.isdir(name):
                        for name_ in os.listdir(name):
                            name_ = os.path.join(name, name_)
                            size = dirsize(name_)
                            if size >= 0:
                                dir_list.append((size, name_))
                        continue
                size = dirsize(name)
                if size >= 0:
                    dir_list.append((size, name))
        finally:
            infile.close()
    except IOError, error:
        print 'Kann Datei "%s" nicht lesen!' % DIRFILE
    return dir_list


def divide(dir_list):
    '''Verzeichnisse auf mehrere Medien verteilen.'''
    dir_list.sort(reverse=True)
    dest_list = []
    to_large = []
    for source_size, source_filename in dir_list:
        if source_size > MAXSIZE:
            to_large.append(source_filename)
            continue
        for dest_size, dest_items in dest_list:
            if (dest_size[0] + source_size) <= MAXSIZE:
                dest_size[0] += source_size
                dest_items.append(source_filename)
                break
        else:
            dest_list.append([[source_size], [source_filename]])
    return dest_list, to_large


def main():
    dir_list = make_dir_list()
    if not dir_list:
        return
    cont, to_large = divide(dir_list)
    if to_large:
        print 'Zu groß für ein Medium sind:\n%s' % (', '.join(to_large))
    for i, (size, cont_) in enumerate(cont):
        print 'Schreibe Medium Nr. %i' % (i + 1)
        os.system(NEROCMD % (i + 1, '" "'.join(cont_)))


if __name__ == '__main__':
    main()
Die zu sichernden Dateien bzw. Ordner befinden sich in einer Datei names Dirs.txt. Der Parameter 'S' am Ende führt dazu, dass die darin enthaltenen Ordner/Dateien einzeln erfasst werden. Das kürzt die Eingabe ab. dirsize berechnet die Größe eines Verzeichnisses. divide entspricht weitgehend Gerolds Script.
MfG
HWK
Antworten