Kopieren individuell

Du hast eine Idee für ein Projekt?
JohnWorks
User
Beiträge: 10
Registriert: Freitag 15. April 2011, 12:20

Hallo Community,

wie man sehen kann, bin ich nun ganz frisch dabei :D Ich komme von der Php-Seite und versuche nun einen praktischen Einstieg in Python zu finden. Erfolgreich habe ich nun Python 3.2 und PyQt4 installiert. "Hello World"-Tutorials habe ich nun auch abgearbeitet und nun solls zum "ersten Projekt gehen". Ich habe auf einem Server ein Ordner, den ich immer auf einen USB-Stick kopiere, dies mache ich im Moment mit einem Batch-File, dies soll nun durch ein Python-Programm erledigt werden.

Was soll passieren:
> Netzlaufwerke sollen getrennt werden
> Netzlaufwerk soll verbunden werden

> Größe des zu kopierenden Ordners soll ermittelt werden
> Freier Speicherplatz auf dem USB-Stick soll ermittelt werden

> USB-Stick leeren
> Ist genügend freier Speicherplatz vorhanden, Ordner kopieren

> zu kopierenden Ordner verschieben

> Netzlaufwerk trennen
> USB-Stick auswerfen

> Es gibt eine SQL-Datenbank in der ein Eintrag vorgenommen wird (Protokollierung)

Alle Variablen sollen durch Dialoge ausgewählt werden (Bsp: Netzlaufwerk-Buchstabe, Pfad zum Netzlaufwerk, Benutzername/Kennwort, Zielpfad)!
Nachher soll alles in eine Exe gepackt werden. Ich denke das ganze Skript kann man schrittweise realisieren.

Mein Vorgehen:

Erstmal ein Python-Skript schreiben,
mit Ui verknüpfen,
DB-Eintrag.

Meine Ideen zu diesem Progamm:
> Netzlaufwerk soll getrennt werden

Code: Alles auswählen

os.system('net use [LaufwerkbuchstabeInput] /delete')
> Netzlaufwerk soll verbunden werden

Code: Alles auswählen

os.system('net use [LaufwerkbuchstabeInput] [PfadInput] [Kennwort] [Benutzername]')
> Größe des zu kopierenden Ordners soll ermittelt werden

Code: Alles auswählen

[GrößeInput] = os.stat('[LaufwerkbuchstabeInput]')
[GrößeInput].st_size 
> Freier Speicherplatz auf dem USB-Stick soll ermittelt werden

Code: Alles auswählen

[GrößeOutput] = os.stat('[LaufwerkbuchstabeOutput]')
[GrößeOutput].st_size 
> USB-Stick leeren

Code: Alles auswählen

os.rmdir('[LaufwerkbuchstabeOutput]')
> Ist genügend freier Speicherplatz vorhanden, Ordner kopieren

Code: Alles auswählen

If [GrößeOutput] > [GrößeInput]:
shutil.copy2('[LaufwerkbuchstabeInput]', '[LaufwerkbuchstabeOutput]')
else:
print 'error'
> zu kopierenden Ordner verschieben

> Netzlaufwerk trennen

Code: Alles auswählen

os.system('net use [LaufwerkbuchstabeInput] /delete')
> USB-Stick auswerfen

Code: Alles auswählen

SPÄTER
> Es gibt eine SQL-Datenbank in der ein Eintrag vorgenommen wird (Protokollierung)

Code: Alles auswählen

SPÄTER
Was kann man davon halten?! Irgendwo grobe Fehler oder gibt es andere bessere Methoden?
HORSEPOWER
IS NOTHING WITHOUT
BRAINPOWER.
BlackJack

@JohnWorks: Statt `os.system()` solltest Du das `subprocess`-Modul verwenden.

Du willst nicht die Grösse des zu kopierenden Ordners sondern die Summe der Grössen aller Dateien in und unterhalb des Ordners. Das gibt es nicht als Attribut, da musst Du alle Unterordner und Dateien abfragen. → `os.walk()`.

Speicherplatz auf dem Zieldateisystem kann man natürlich auch nicht so ermitteln, denn das ermittelt ja die *belegte* Grösse des Ordners (selbst) und nicht wie viel da frei ist. Das bekommt man mit `os.statvfs()` heraus.

Man kann nur leere Ordner mit `rmdir()` entfernen. Schau Dir mal das `shutil`-Modul genauer an.

Der Test auf genug Speicherplatz ist nicht genau und im Grunde auch nicht wirklich mit vertretbaren Aufwand genau hin zu bekommen. Du solltest also auf jeden Fall prüfen ob alles kopiert werden konnte.
JohnWorks
User
Beiträge: 10
Registriert: Freitag 15. April 2011, 12:20

@BlackJack: Also erstmal denke für die Tipps! Mit der Ordnergrößeermittlung sieht das ganze unter Windows ja nicht so leicht aus! os.statvfs() funktioniert ja nur unter Linux... Kann ich denn zwei Ordner miteinander vergleichen?

Code: Alles auswählen

#!/usr/bin/python

import subprocess

subprocess.call("net use * /delete")
subprocess.call("net use S: \\192.168.1.1\Users\")
Leider funktioniert die Ausführung nicht!
HORSEPOWER
IS NOTHING WITHOUT
BRAINPOWER.
lunar

@JohnWorks: Lies doch bitte die Dokumentation des "subprocess"-Moduls. Dort steht beschrieben, dass Befehle als Liste angegeben werden müssen. Zudem funktionieren Shell-Funktionen wie "*" nicht. Du musst die Liste der Dateien selbst erzeugen, und an den Befehl übergeben.
deets

@lunar

Das ist natuerlich beides Unsinn.

Code: Alles auswählen

>>> subprocess.call("mkdir -p /tmp/foobar/baz", shell=True)
0
>>> p = subprocess.Popen("ls /tmp/foo*", shell=True, stdout=subprocess.PIPE)
>>> p.communicate()
('baz\n', None)
Aber ich wuerde auch in jedem Fall die Kommandos selbst als Liste uebergeben, da man sich damit laestiges escaping spart.
deets

@JohnWorks

Ich habe kein Windows, darum kann ich das nicht direkt nachvollziehen. Aber zwei Anmerkungen zu deinen Kommandos:

- wenn du eine Expansion von Filenamen mittels * willst, musst du shell=True als Argument uebergeben
- ebenso, wenn du Kommandos als ganze Strings uebergibst.
- besser ist es, Kommandos als Liste von Strings zu uebergeben. Dann funktioniert sowas wie "*" aber *nicht* mehr! Du muesstest dann die Liste der Argumente explizit uebergeben.
- deine Netzwerkpfade sind ebenfalls problematisch, denn der Backslash "\" ist in Python Strings ein Sonderzeichen. Er wird fuer sogenannte escape-sequences benutzt. Um in einem normalen String-Literal einen Backslash zu erzeugen, muss man ihn *zweimal* angeben. Also "\\\\rechner\\volume". Alternativ gibt es die sogenannten "raw-strings" in Python, die genau das nicht verlangen: r"\\rechner\volume". Beachte das r vor dem ".
lunar

@deets: Ist mir durchaus bekannt, und der OP wäre bei der Lektüre der Dokumentation sicherlich auch darauf gestoßen. Dann aber eben begleitet von der deutlichen Warnung, die von der Benutzung dieser Option nachdrücklich abrät, und dafür gute Gründe nennt. Das hätte dem OP ermöglicht, selbst zu entscheiden, ob er die Nachteile dieser Option zum Zwecke der Bequemlichkeit in Kauf nimmt oder nicht. Aber das ist ja nun überflüssig, weil Du nicht umhin könntest, ihm die schöne, schnelle Komplettlösung vorzulegen.

Hätte ich gewusst, dass Du auch bei einer solchen Kleinigkeit nur um des Widersprechens willen widersprichst, hätte ich gleich den entsprechenden Abschnitt der Dokumentation in voller Länge hierher kopiert, um jeglichen Missverständnissen von vorne herein vorzubeugen. Im Übrigen gestehe ich natürlich selbstverständlich ein, dass Du Recht hast, und mein Beitrag in dieser Hinsicht unvollständig war, und hoffe inständig, dass es Deinem Ego gut tut.

PS: Ganze Zeichenketten zu übergeben, funktioniert unter Windows im Übrigen auch ohne "shell=True".
deets

@lunar

Wer Korinthen kackt, muss sich nicht wundern, wenn man ihn deutlich darauf hinweist, wenn er Falsches von sich gibt.

Entweder ist man bereit, den hier gegebenen Antworten zuzugestehen, dass sie in ihrer Essenz richtig sind, ohne sich unnoetig in Details zu versteigen. Gerne.

Aber dann verzichten wir beim naechsten mal auch auf falsche Belehrungen darueber, was "proprietar" bedeutet. Oder ob es sinnvoll ist, jemanden zu raten, den ConfigParser zu verwenden, wo doch drei Zeilen "trivialem" Code genuegen. Auf die der OP zwar im Leben nicht gekommen waere, aber was soll's.

Insofern - ja, da gestehe ich gerne: das hat Spass gemacht. Denn Besserwissertum ist keine Einbahnstrasse, und wenn du meinst mir an den Karren pinkeln zu muessen - meine Blase ist gross, da halte ich dann gerne gegen.

Darueber hinaus finde ich deine Antwort trotzdem falsch. Zu behaupten, es "muesse" und "es geht nicht" ist numal nicht richtig. Diese Features gibt es, und auch mit gutem Grund. Das man sie mit Vorsicht geniessen sollte wissen wir beide. Aber ich bin nicht der Meinung, dass man so tun sollte, als ob es sie nicht gibt.
lunar

@deets: Ich glaube, diesen Teil der Diskussion setzen wir im Interesse des OP besser im Privaten fort ...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Wie auch immer, korrigiert mich wenn ich falsch liege aber war die Expansion von ``glob``s unter Windows nicht Aufgabe des aufgerufenen Programmes statt der Shell? Hatte schon seit Jahren nicht mehr mit Windows zu tun, meine aber sowas gelesen zu haben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
daemonTutorials
User
Beiträge: 171
Registriert: Sonntag 6. Februar 2011, 12:06
Kontaktdaten:

Ein kleiner Tipp für die SQL DB. Nimm die intigrierte sqlite-Datenbank. Lese die mit einem extra Skript aus.
So hast du alles bei Python.
LG Maik
JohnWorks
User
Beiträge: 10
Registriert: Freitag 15. April 2011, 12:20

Soooo über Ostern habe ich auch mal ein wenig rumprobiert!
Rausgekommen ist folgendes:

Code: Alles auswählen

#!/usr/bin/python

import os

def erstelleOrdner(USB):
    """Erstellt neuen Ordner.

    Erstellt neuen Ordner mit Hilfe von Import OS."""

    if os.path.isdir(USB):
        os.chdir(USB)
        if os.path.isdir('Backup'):
            print 'Verzeichniss schon vorhanden!'
            AbfrageLoeschen = raw_input('Soll das Verzeichnis geloescht werden (Y/N)? : ')
            if AbfrageLoeschen == 'Y' or 'y' :

                #Methode die Ordner leer auch wenn Files drin sind!!!
                
                print 'Verzeichnis geloescht!'
                os.mkdir('Backup')
                print 'Neues Verzeichnis erstellt.'          
            else:
                print 'Abbruch!'
                return'False'
        else:
            os.mkdir('Backup')
            print 'Verzeichniss erstellt!'
    else:
        print 'USB-Laufwerk ', USB, ' nicht gefunden!'

    

USB = 'C:\Python27\Test\Usb'


erstelleOrdner(USB)

print 'Ende'
Das Problem bei der Sache ist, dass wenn ich ein File in dem Verzeichnis ist, dass Ganze mit dem Löschen nicht mehr klappt. Auch wäre es es eigentlich schöner, wenn ich mit einer return-Fkt arbeiten würde, die einen Wert nach durchlaufen der Fkt zurück gibt. Sollte man nochmals Testen ob wirklich ein Verzeichnis angelegt wurde?!

So gleich mal in die Unibib und "O'Reillys: Python : kurz & gut" ausleihen (jmd damit Erfahrungswerte?).
HORSEPOWER
IS NOTHING WITHOUT
BRAINPOWER.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Schau Dir Deine Eingabeauswertung noch mal an:

Code: Alles auswählen

In [1]: foo = "z"

In [2]: if foo == "Y" or "y":
   ...:     True
   ...:     
   ...:     
Out[2]: True
Ein paar Anmerkungen noch:

- Der Styleguide PEP8 empfiehlt für Funktionsnamen die Verwendung von lowercases_with_underscores. Ausnahmen bilden Funktionen / Methoden im Kontext von Libs, welche traditionell auf mixedCase setzen (Qt Bindings z.B.)

- der `os.chdir()`-Aufruf ist imho nicht notwendig.

- Pfade solltest Du als Raw-Strings angeben:

Code: Alles auswählen

USB = r'C:\Python27\Test\Usb'
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JohnWorks
User
Beiträge: 10
Registriert: Freitag 15. April 2011, 12:20

Hyperion hat geschrieben: - der `os.chdir()`-Aufruf ist imho nicht notwendig.
Wieso? Wenn ich nicht in das Verzeichnis wechsele, dann kann er doch auch den Ordner "Backup" nicht finden.
HORSEPOWER
IS NOTHING WITHOUT
BRAINPOWER.
BlackJack

@JohnWorks: Man sollte besser auf `os.chdir()` verzichten und stattdessen den Pfad immer komplett angeben. Also in diesem Fall mit `os.path.join()` den Pfad zu dem Ordner mit dem Ordnernamen verbinden. Das Arbeitsverzeichnis ist eine Einstellung, die den gesamten Prozess betrifft und solche globalen Werte sollte man nicht einfach ändern.
JohnWorks
User
Beiträge: 10
Registriert: Freitag 15. April 2011, 12:20

Und hat nun auch noch jemand eine Idee Verzeichnisse (samt Daten und Unterverzeichnissen) von A nach B kopiere?
Gibt es noch gute Einführende Beispiele zum Modul os und shutil?
HORSEPOWER
IS NOTHING WITHOUT
BRAINPOWER.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

JohnWorks hat geschrieben:Und hat nun auch noch jemand eine Idee Verzeichnisse (samt Daten und Unterverzeichnissen) von A nach B kopiere?
Gibt es noch gute Einführende Beispiele zum Modul os und shutil?
Hast Du Dir die Doku mal genau angeguckt und ein wenig herumprobiert? So schwer sollte das doch nicht sein...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JohnWorks
User
Beiträge: 10
Registriert: Freitag 15. April 2011, 12:20

Code: Alles auswählen

#!/usr/bin/python

import shutil
import datetime

#Pfandangeben USB, NETZWERKLAUFWERK
USB = r'C:\Python27\Test\Usb'
NETZLAUFWERK = r'C:\Python27\Test\Netzlaufwerk'

#Ermittlung der Zeit fuer Pfadangabe
now = datetime.datetime.now()
d = now.date()
t = now.utcnow()

#Ziel auf USB
DESTINATION = USB + now.strftime("\%y%m%d%H%M%S")

shutil.copytree(NETZLAUFWERK, DESTINATION)

print 'Ende'
So mit ein bisschen einlesen hat das nun auch alles geklappt. Nun habe ich noch eine Frage die ich mir beim einlesen nicht beantworten konnte. Und zwar möchte ich gerne in Prozent wissen wieviel kopiert worden ist (Ziel: Später soll ein GUI dazukommen über die man das ganze bedienen soll! Und dort soll dann ein Balken angezeigt werden wieviel Prozent kopiert sind).

Zweite Sache, wie und wo speichert man am besten die Konfigurationsdaten (in meinem Fall erstmal die Beiden Pfade, später sollen noch andere Einstellungsmöglichkeiten hinzukommen?).
HORSEPOWER
IS NOTHING WITHOUT
BRAINPOWER.
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

JohnWorks hat geschrieben:Und zwar möchte ich gerne in Prozent wissen wieviel kopiert worden ist (Ziel: Später soll ein GUI dazukommen über die man das ganze bedienen soll! Und dort soll dann ein Balken angezeigt werden wieviel Prozent kopiert sind).
Das ist leider nicht so einfach. Dieser Comic illustriert ein bisschen, das auch andere Programmierer damit Schwierigkeiten haben.

Leider ist nur sehr schwer abzuschaetzen, wie lange das Kopieren in der Zukunft aussieht.
Z.B. brauchen kleine Dateien tendentiell laenger als grosse (bezogen auf ihre Groesse).

Du muesstest, um es einigermassen praezise zu gestalten, die Dateigroessen vorher einlesen und mit einer Formel die benoetigte Dauer ausrechnen.
Vermutlich waere das aber dann voellig vom Rechner abhaengig.
Ausserdem wuerde sich dadurch der ganze Prozess verlaengern (Alles Dateien vor dem Kopieren durchgehen dauert auch seine Zeit).
lunar

@Liffi: Der OP hat nicht von Zeit gesprochen. Eine prozentuale Anzeige des Fortschritts kann sich auch beziehen auf die Anzahl der bereits kopierten Bytes im Verhältnis zur Gesamtgröße aller zu kopierenden Dateien. Eine solche Anzeige ist relativ zuverlässig.

@JohnWorks: Du musst eben vorher das zu kopierende Verzeichnis durchlaufen, die Anzahl der Dateien sowie ihre Größe bestimmen, und anschließend nochmals durchgehen, um zu kopieren, wobei Du jetzt den Fortschrittsbalken anzeigen und aktualisieren kannst. "shutil.copytree" lässt sich dann natürlich nicht verwenden.
Antworten