Dateipfad zusammensetzen

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
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Hi,
wieder ein Problem :oops:

mit diesem Script:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import shutil
suchpfad = '/home/thomas/script/pytest'
zielpfad = '/home/thomas/musik'
dateiendung = '.mp3', '.flac', 'wav'
test = []
sauber_liste = []

def verschieben():
    print('Kopiere:', os.path.join(os.path.dirname(alt), os.path.basename(alt)))
    print('Nach:',neu)
    ##shutil.copytree(alt, neu)
    ##shutil.move(alt, neu)
    
for pfad, verzeichnis, dateien in os.walk(suchpfad, topdown=False):
    for d_name in dateien:
        d_endung = d_name.endswith(dateiendung)
        d_pfad = os.path.join(pfad, d_name)
    if d_endung:
        musik_verz = os.path.dirname(d_pfad)
        test.append(musik_verz)
        sauber_liste = sorted(set(test), key = test.index)#wegen doppelter einträge in liste
sauber_liste.remove(suchpfad)#suchpfad aus liste löschen
for alt in sauber_liste:
    neu = os.path.join(zielpfad, os.path.basename(alt))
    verschieben()
###****LOSE LIEDER****    
##    if alt == suchpfad:
##        for lose_lieder in os.listdir(alt):
##            pfad_lose_lieder = os.path.join(alt, lose_lieder)
##            if os.path.isfile(pfad_lose_lieder):
##                print('Loses Lied:',lose_lieder)
bekomme ich diese Ausgabe:
[Kopiere: /home/thomas/script/pytest/Hannes_Wader_-_7_Lieder
Nach: /home/thomas/musik/Hannes_Wader_-_7_Lieder
Kopiere: /home/thomas/script/pytest/BlackSabbath_Best_off/CD1
Nach: /home/thomas/musik/CD1
Kopiere: /home/thomas/script/pytest/BlackSabbath_Best_off/CD2
Nach: /home/thomas/musik/CD2
/quote]

Nun möchte ich natürlich nicht das /home/thomas/musik/CD2 ausgegeben wird, sondern "/home/thomas/musik/BlackSabbath_Best_off/CD2" und "/home/thomas/musik/BlackSabbath_Best_off/CD1".
Wie (womit) komme ich an "BlackSabbath_Best_off"?

mit os.path.dirname() bekomme ich dies:
os.path.dirname('/home/thomas/script/pytest/BlackSabbath_Best_off')
'/home/thomas/script/pytest'
oder das:
os.path.dirname('/home/thomas/script/pytest/BlackSabbath_Best_off/CD1')
'/home/thomas/script/pytest/BlackSabbath_Best_off'
Gruß
wattwurm
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Es gibts sicher einen speziellen Befehl dafür aber split und os.sep könnten ganz nützlich sein.

PS: Bei wav fehlt ein Punkt.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Seit Python 3.4 gibt es mit dem Modul pathlib eine komfortable Möglichkeit an Endungen und Pfadteile heranzukommen. Du mußt halt eine Regel definieren und dafür eine Funktion programmieren, wann Du welche Pfadtiefe kopieren willst.
Ich bezweifle, dass Dein Programm das macht, was Du willst. Was soll test sein? Was ist sauber_liste? Und wann werden die Listen erzeugt? Das macht für mich alles keinen Sinn.
Dann solltest Du lernen, was Funktionen sind; pack alles in Funktionen, benutze keine globalen Variablen und achte sorgfältig darauf, wann welche Liste erzeugt wird. Was soll denn das Sortieren bewirken? Wieso glaubst Du, dass Du doppelte Einträge bekommst?

@darktrym: der andere spezielle Befehl heißt os.path.split. os.sep darf man nicht für Pfadoperationen verwenden.
BlackJack

Ergänzung: Das gesuchte ”Gegenteil” von `os.path.dirname()` ist `os.path.basename()`.
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Das macht für mich alles keinen Sinn.
Das glaube ich dir gerne, aber so sieht es aus wenn ein Heizungsbauer meint er müsse jetzt mal was programmieren :mrgreen:
pack alles in Funktionen
Meinst Du das so?

Code: Alles auswählen

def xyz():
    mach was...

def main():
    xyz()
    mach weiter
    
if __name__ == '__main__':
    import ...
    main()
benutze keine globalen Variablen
heist, in den Funktionen erzeugen?
achte sorgfältig darauf, wann welche Liste erzeugt wird.
Und wann? Wenn man sie braucht und in den Funktionen?
Was soll denn das Sortieren bewirken? Wieso glaubst Du, dass Du doppelte Einträge bekommst?
Sortieren war wohl unnötig, aber es war irgend ein Eintrag doppelt vorhanden, deswegen "set(test)"
Was soll test sein? Was ist sauber_liste?
Mir fallen immer keine passende Namen ein :K

Danke das Ihr immer antwortet!
wattwurm
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

wattwurm hat geschrieben: Mir fallen immer keine passende Namen ein :K
Das ist aber schlecht! Denn irgend eine Idee hast Du ja im Kopf, *was* Du in Python formulieren willst.

Wenn ich meinen Sortieralgorithmus mit einem Namen wie ``sort`` benenne, drückt das doch mehr aus, als sagen wir mal ``mache_halt_was_ganz_tolles``, oder? Und eine Liste von GPIO-Ports "mittagsgerichte" zu nennen, dürfte eher auch wenig informativ sein ;-) Selbiges gilt aber auch für ``a``, ``b`` und ``c`` oder andere komplett nichts sagende Namen.

Gute Namen zu finden ist schwer! Gute Namen zu finden ist aber so *verdammt wichtig*! Manchmal gibt es einfach auch Schwierigkeiten, weil man viel zu viel "machen" will - dies trifft natürlich insbesondere auf Funktionen- / Methoden- und Klassennamen zu.

Ich glaube viele Anfänger käpfen viel zu viel mit der Syntax und allgemeinen Semantik und denken, dass die bei so "trivialen" Dingen wie Namen *schnell* etwas hinschreiben können, um voran zu kommen, frei nach dem Motto "vor dem Gleichheitszeichen ist 's einfach, danach wird 's kompliziert...". Das ist leider ein Trugschluss - denn im späteren Verlauf zahlt man dafür dann die Zeche ;-)

Wenn Du wirklich Interesse am "besser Werden" hast, dann empfehle ich Dir mal Clean Code. Vieles darin ist insbesondere für Anfänger sehr gut geeignet.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@wattwurm: @wattwurm: Ich sehe nicht wie da ein doppelter Eintrag in der `os.walk()`-Schleife zustande kommen kann. Wobei das nicht so ganz einfach ist dem Code zu folgen weil der so verdammt viel unsinniges und unnötiges macht. Und fehlerhaft ist er zudem auch noch.

Das fängt mit dem ``topdown=False`` an was unnötig ist weil es keinen Unterschied im Ergebnis macht.

Dann kommt der Fehler: Du gehst alle Namen in `dateien` durch und testest ob die jeweilige Datei eine bestimmte Endung hat und bastelst Dir `d_pfad` zusammen. Effektiv haben `d_endung` und `d_pfad` damit den Wert der Ausdrücke für den *letzten* Dateinamen in `dateien`. Alle anderen hättest Du gar nicht prüfen brauchen. Da die Reihenfolge in `dateien` nicht garantiert ist läuft das darauf hinaus ob zufällig der letzte Dateiname in dieser Liste eine der Endungen hat auf die geprüft wird. Wenn in einem Verzeichnis also zum Beispiel die Musikstücke eines Albums liegen und eine Bilddatei mit dem Albumcover, dann wird dieses Verzeichnis in die Liste aufgenommen, oder halt auch nicht.

Falls das zufällig der Fall ist, dann trennst Du den Pfadanteil von `d_pfad` ab. `d_pfad` ist entstanden aus dem Verbinden vom Pfadanteil mit dem Dateinamen. Also bekommt man den Pfadanteil den man sowieso schon hat (`pfad`) wieder heraus was die `os.path.join()`/`os.path.dirname()`-Abfolge total sinnfrei macht.

Und dann wird *jedes mal* `sauber_liste` umständlich neu erstellt. Statt das *einmal* *nach* der Schleife zu tun, denn nur der Wert vom letzten Durchlauf wird tatsächlich verwendet. Wobei das wie gesagt unsinnig ist denn die Liste `test` wird effektiv mit (ausgewählten) `pfad`-Werten aus der Schleife über `os.walk()` gefüllt und da jeder Pfad nur einmal besucht wird, können dabei gar keine Doubletten vorkommen, selbst wenn man *alle* `pfad`-Werte sammeln würde nicht.
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

ok ok ok, zurück auf null :)
Ich möchte in Verzeichnissen nach *.mp3, *.flac, *.wav suchen.
Wenn in einen Verzeichnis auch nur eine Datei mit Endung (mp3, ...) vorkommt, soll das ganze Verzeichnis mit sämtlichen Inhalt kopiert (verschoben) werden.

Bin nochmal neu angefangen:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
suchpfad = '/home/thomas/script/pytest'
zielpfad = '/home/thomas/musik'
dateiendung = '.mp3', '.flac', '.wav'

for pfad, verzeichnis, dateien in os.walk(suchpfad):
    for d_name in dateien:
        d_endung = d_name.endswith(dateiendung)
        d_pfad = os.path.join(pfad, d_name)
        if d_endung:
##            print('DATEI:',d_name)
            print(d_pfad)
BIn ich heir schon falsch angefangen?

Ausgabe:
/home/thomas/script/pytest/Adele.21--05-Set.Fire.To.The.Rain.flac
/home/thomas/script/pytest/Robin_Mcauley_-_I_Stole_Your_Love.mp3
/home/thomas/script/pytest/ABBA_-_Gimme!_Gimme!_Gimme!.mp3
/home/thomas/script/pytest/Baltimora_-_Tarzan_Boy.mp3
/home/thomas/script/pytest/Avicii-_Wake_Me_Up_(Radio_Edit).flac
/home/thomas/script/pytest/ABBA_-_Knowing_Me_Knowing_You.mp3

/home/thomas/script/pytest/Hannes_Wader_-_7_Lieder/07_-_Kokain.mp3
/home/thomas/script/pytest/Hannes_Wader_-_7_Lieder/01_-_Heute_hier,_morgen_dort.mp3
/home/thomas/script/pytest/Hannes_Wader_-_7_Lieder/05_-_Der_Tankerkönig.mp3

/home/thomas/script/pytest/BlackSabbath_Best_off/CD1/03_-_Black_Sabbath_-_N.I.B..mp3
/home/thomas/script/pytest/BlackSabbath_Best_off/CD1/01_-_Black_Sabbath_-_Black_Sabbath.mp3
/home/thomas/script/pytest/BlackSabbath_Best_off/CD1/02_-_Black_Sabbath_-_The_Wizard.mp3

/home/thomas/script/pytest/BlackSabbath_Best_off/CD2/03_-_Black_Sabbath_-_Snowblind.mp3
/home/thomas/script/pytest/BlackSabbath_Best_off/CD2/02_-_Black_Sabbath_-_Supernaut.mp3
/home/thomas/script/pytest/BlackSabbath_Best_off/CD2/01_-_Black_Sabbath_-_Tomorrow's_Dream.mp3
nun könnte ja bei "/home/thomas/script/pytest/Hannes_Wader_-_7_Lieder/07_-_Kokain.mp3" aufgehört werden und das Verz. Hannes_Wader_-_7_Lieder kopiert werden.

Wie ist das aber bei Black Sabbath? Da würde mir os.path.dirname CD 1 oder CD2 zurückgeben :K

wattwurm
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Falls das zufällig der Fall ist, dann trennst Du den Pfadanteil von `d_pfad` ab. `d_pfad` ist entstanden aus dem Verbinden vom Pfadanteil mit dem Dateinamen. Also bekommt man den Pfadanteil den man sowieso schon hat (`pfad`) wieder heraus was die `os.path.join()`/`os.path.dirname()`-Abfolge total sinnfrei macht.
Dann brauch ich os.path.dirname gar nicht und könnte auch

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
suchpfad = '/home/thomas/script/pytest'
zielpfad = '/home/thomas/musik'
dateiendung = '.mp3', '.flac', '.wav'

for pfad, verzeichnis, dateien in os.walk(suchpfad):
    for d_name in dateien:
##        d_pfad = os.path.join(pfad, d_name)
        d_endung = d_name.endswith(dateiendung)
    if d_endung:
        print(pfad)
schreiben?

Die Ausgabe ist dann auch freundlicher:
>>>
/home/thomas/script/pytest
/home/thomas/script/pytest/Hannes_Wader_-_7_Lieder
/home/thomas/script/pytest/BlackSabbath_Best_off
/home/thomas/script/pytest/BlackSabbath_Best_off/CD1
/home/thomas/script/pytest/BlackSabbath_Best_off/CD2
Ist das jetzt ein klitzekleines bisschen besser?

Schönes Wochenende
wattwurm
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also zum einen sind die Namen teilweise doof (``d_name`` - WTF?), zum anderen ist das ziemlich ineffizient, wenn ich den Code richtig verstehe!

Dir reicht es doch, wenn *ein* Name in dem Verzeichnis auf *eine* Endung endet. Wieso printest Du nicht einfach dann den Pfad und brichst die innere Schleife ab?

Oder man schreibt es gleich explizit "lazy":

Code: Alles auswählen

filenames = ("foo.txt", "bar.mp3", "foobar.flac")
suffixes = (".mp3", ".flac", ".wav")
any(filename.endswith(suffixes) for filename in filenames)
> True

filenames = ("foo.txt", "bar.ogg", "foobar.png")
any(filename.endswith(suffixes) for filename in filenames)
> False
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@wattwurm: Es macht auf dem Weg zum Programmfehler nun zumindest einen unnötigen Umweg weniger. Durch *alle* Dateinamen zu iterieren ist aber weiterhin unnötig, denn das hier würde ohne Schleife (fast) den gleichen Effekt haben:

Code: Alles auswählen

for pfad, verzeichnis, dateien in os.walk(suchpfad):
    if dateien[-1].endswith(dateiendung):
        print(pfad)
Das Problem ist was passiert wenn ein Verzeichnis gar keine Dateien enthält. Dein Code würde dann den Pfad aus dem letzten Durchlauf wiederholen — ups, hier könnte vielleicht die Quelle Deiner Duplikate liegen die eigentlich gar nicht vorkommen sollten. :-) Bei meinem würde ein `IndexError` ausgelöst. Und das `topdown` bei `os.walk()` macht vielleicht doch Sinn wenn nämlich in Verzeichnissen mit Musikdateien Verzeichnisse mit Musikdateien liegen, damit es später nicht beim Verschieben zu Situationen kommen kann in denen man das ”höhere” Verzeichnis mit dem enthaltenen schon verschoben hat. So etwas sollte man dokumentieren. Bei Deinem ursprünglichen Beitrag macht es trotzdem keinen Unterschied weil Du die korrekte Reihenfolge für das Verschieben durch das sortieren der Pfade wieder zerstört hast.
BlackJack

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
import os
import shutil

SOURCE_PATH = '/home/thomas/script/pytest'
TARGET_PATH = '/home/thomas/musik'
AUDIO_SUFFIXES = ('.aac', '.flac', '.m4a', '.mp3', '.ogg', '.wav')


def iter_audio_paths(path, suffixes=AUDIO_SUFFIXES):
    for root, _, filenames in os.walk(path, topdown=False):
        if (
            not os.path.samefile(path, root) and
            any(filename.endswith(suffixes) for filename in filenames)
        ):
            yield root


def main():
    for path in iter_audio_paths(SOURCE_PATH):
        shutil.copytree(path, TARGET_PATH)


if __name__ == '__main__':
    main()
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Ui, danke BlackJack!
Das muß ich erstmal sacken lassen.

wattwurm
Antworten