Dateien auflisten

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.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Hallo zusammen

Wieder einmal ein Problem....leider.

Ich habe folgenden Code erfasst:

Code: Alles auswählen

from pathlib import Path

BASEPATH = Path("C:/Users/Startklar/Desktop/Belege/")

for PDF in BASEPATH.glob("*.pdf"):
    print(PDF)

print(PDF.stem.split("_"))

date, number, name = PDF.stem.split("_")

Bei print(PDF.stem.split("_")) zeigt er mir leider nicht die gesamten pdf-Dateien an sondern nur die letzte. Ist das normal oder kann ich das ändern? Ich würde gerne prüfen, ob sämtliche Dateinamen wunschgemäss getrennt werden.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Konstanten schreibt man komplett gross, PDF ist aber keine Konstante. Und natürlich wird nur die letzte pdf-Datei getrennt, weil diese Zeilen nach der Schleife stehen und nicht in der Schleife.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Danke, so einfach kann das sein :-). Habe PDF jetzt auch klein geschrieben :-)
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

In eine zweiten Schritt möchte ich alle pdf Dateien mit einem speziellen Namen "number" unter einem entsprechenden Pfad ablegen. Ich habe dafür einen Filter eingebaut, in welchem das definiert sein soll. Das sieht so aus:

Code: Alles auswählen

import re
from pathlib import Path
import shutil

BASEPATH = Path("C:/Users/Startklar/Desktop/Belege/")

for pdf in BASEPATH.glob("*.pdf"):
    print(pdf.stem.split("_"))

date, number, name = pdf.stem.split("_")

FILTERS = [
    ("C:/Users/Startklar/Desktop/Belege/XBIT", "233-00408710")
]

def main():
    for number in FILTERS:
        destination = "C:/Users/Startklar/Desktop/Belege/XBIT"
        for sourcefile in BASEPATH.glob(f"*{number}*.pdf"):
            sourcefile.rename(sourcefile, destination)

if __name__ == "__main__":
    main()
Beim Ausführen passiert allerdings überhaupt nichts.... Weiss jemand weshalb?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn "nichts" passiert, dann packt man an passenden Stellen `print` hin, um zu schauen, ob die Variablen Werte enthalten, die man auch erwarten würde. Z.B. ist `number` das, was Du denkst, dass es ist? (Spoiler: nein)
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Wenn ich, gleich nach

Code: Alles auswählen

date, number, name = pdf.stem.split("_")

print(number) 
schreibe kommt der gewünschte Wert. Der Code sollte das also begriffen haben. Dann muss ich wohl davon ausgehen, dass er im Filter die Zahlenkombination nicht der "number" zuweist richtig?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Du musst das schon da ausgeben lassen, wo du es benutzt - nicht irgendwo nach einer Zuweisung, die möglicherweise hinterher überschrieben wird.
Der Code muss übrigens gar nichts begreifen. Das sind ja nur Anweisungen, die _du_ schreibst. Also musst du den Code begreifen.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Ich habe den Filter angepasst und die Bezeichnungen der "Spalten" hinzugefügt. Das sieht jetzt wie folgt aus:

Code: Alles auswählen

import re
from pathlib import Path
import shutil

BASEPATH = Path("C:/Users/Startklar/Desktop/Bbelege/")

for pdf in BASEPATH.glob("*.pdf"):
    print(pdf.stem.split("_"))

date, number, name = pdf.stem.split("_")

FILTERS = [
    ("C:/Users/Startklar/Desktop/Belege/XBIT", "233-00408710")
]

def main():
    for place, number in FILTERS:
        destination = "C:/Users/Startklar/Desktop/Belege/XBIT/"
        for sourcefile in BASEPATH.glob(f"*{number}*.pdf"):
            sourcefile.rename(sourcefile, destination)

if __name__ == "__main__":
    main()
Es kommt mir dabei folgende Fehlermeldung: rename() takes 2 positional arguments but 3 were given

Ich sehe nicht, wo ich drei Argumente gebe... Ich möchte nicht, dass die Datei umgeschrieben wird. Sie soll nur 1 zu 1 in den angegebenen Pfad verschoben werden.

P.S. Ich weiss, dass der Code nur das macht was ich ihm sage, nur weiss ich oft nicht was ich sage ;-)

Habe gerade noch folgendes Bemerkt. Die destination ist natürlich nicht immer die gleiche sondern sollte vom Filter genommen werden, welcher manuell ergänzt. Wie kann dies eingebaut werden?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei Methoden ist das erste Argument automatisch die Instanz. Und dann gibst Du noch explizit zwei weitere an. Was man rename übergeben muß, steht in der Dokumentation.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Der rename Code müsste meiner Meinung nach stimmen, da diese in der Dokumentation wie folgt beschrieben ist:

Code: Alles auswählen

path.rename(pathlib.Path(directory, new_name))
oder was übersehe ich hier?

Ich glaube aber, dass ich vom Weg abgekommen bin. Ich möchte nämlich die Dateien nicht neu benennen sondern sie anhand des Filters verschieben. So soll z.B. die Nummer 233-00408710 in einen Ordner verschoben werden, für welchen in manuell im Filter den Pfad angebe. In diesem Fall müsste ich wohl eher mit .replace arbeiten oder?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Umbenennen und verschieben ist das gleiche. Und du hast dich da verhaspelt, du musst schon zwei Argumente - aktueller & neuer Pfad - an rename uebergeben. Du gibst nur eines.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Oh jetzt habe ich es gemerkt. Ich habei bei sourcefile und destination den gleichen Pfad drin, shame on me und DANKE

Wie kann ich die destination auf den Filter beziehen? Je nach Nummer gibt es einen anderen Pfad und der Code sollte dabei auf den Filter zurückgreifen und den für die Nummer bestimmten Pfad wählen.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

Bebbi hat geschrieben: Dienstag 26. April 2022, 19:41 Der rename Code müsste meiner Meinung nach stimmen, da diese in der Dokumentation wie folgt beschrieben ist:

Code: Alles auswählen

path.rename(pathlib.Path(directory, new_name))
Und der Methode rename() werden dabei wieviele Parameter übergeben? Genau: zwei. einmal "path", also: die Path-Instanz, auf der die Methode aufgerufen wird, und in den Klammern dann "pathlib.Path(directory, new_name)"... In die Klammern gehört also nur ein Parameter.
Bebbi hat geschrieben: Dienstag 26. April 2022, 19:41 Ich möchte nämlich die Dateien nicht neu benennen sondern sie anhand des Filters verschieben. So soll z.B. die Nummer 233-00408710 in einen Ordner verschoben werden, für welchen in manuell im Filter den Pfad angebe. In diesem Fall müsste ich wohl eher mit .replace arbeiten oder?
Am Schönsten wäre natürlich eine Funktion, der Du den Quelldateinamen übergibst, die dann daraus den Zieldateinamen ermittelt und zurückgibt... Wenn Du ein aktuelles Python in einer Version > 3.10 hast, könnte dessen neues Structural Pattern Matching eine sehr elegante und übersichtliche Lösung ermöglichen.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Besten Dank für den Input, ich hänge aber immer noch.

Ich habe folgenden, angepassten Code:

Code: Alles auswählen

import re
from pathlib import Path
import shutil

BASEPATH = Path("C:/Users/Startklar/Desktop/Belege/")

for pdf in BASEPATH.glob("*.pdf"):
    print(pdf.stem.split("_"))

date, number, name = pdf.stem.split("_")

FILTERS = [
    ("C:/Users/Startklar/Desktop/Belege/XBIT", "233-00408710")
]

def main():
    for place, number in FILTERS:
        destination = "C:/Users/Startklar/Desktop/Belege/XBIT/233-00408710"
        for sourcefile in BASEPATH.glob(f"*{number}*.pdf"):
            sourcefile.rename(BASEPATH(destination))

if __name__ == "__main__":
    main()
Meiner Meinung nach müsste der Code folgendes bedeuten: Die Datei soll von BASEPATH also dem Verzeichnis "C:/Users/Startklar/Desktop/Belege/" in das Verzeichnis destination verlegt werden. Unter destination habe ich folgendes Verzeichnis drin "C:/Users/Startklar/Desktop/Belege/XBIT/233-00408710".

Jetzt kommt aber folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/Users/Startklar/AppData/Local/Programs/Python/Python38/Versuch I.py", line 23, in <module>
    main()
  File "C:/Users/Startklar/AppData/Local/Programs/Python/Python38/Versuch I.py", line 20, in main
    sourcefile.rename(BASEPATH(destination))
TypeError: 'WindowsPath' object is not callable
Ich bin mir bewusst, dass Euch dieser Hinweis etwas sagt. Ich kann aber nur daraus lesen, dass WindowsPath" object not collable ist. Was ich so interpretiere dass der WindowsPath nicht aufgerufen werden kann. Welcher WindowsPath? Ich habe ja nur den BASEPATH und die destination und diese Verzeichnisse können sehr wohl aufgerufen werden.

@ LukeNukem: Ich bin mir bewusst, dass es für das Problem wohl einfachere Wege gibt als die jeweiligen Verzeichnisse in einem Filter vorzugeben. Ich muss aber etwas erstellen, was für mich möglich ist. Da ich jetzt schon über meinen Grenzen bin macht es kaum Sinn noch schwierigere Tasks anzugehen. Vielen Dank aber Dir.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Aufrufen meint, das du die Pfade benutzt, als ob sie eine Funktion wären. Sind sie aber nicht. Das hat nichts mit „Ruf mal den Pfad auf“ zu tun. Du willst

/ destination

Statt

(destination)

Letzeres hast du dir ausgedacht.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe Unsinn geschrieben. Du willst Destination als zweites Argument an rename. Wobei das Quatsch ist, weil destination ein Verzeichnis ist. destination / sourcefile.name sollte es wohl sein.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Code außerhalb von `main` ist irgendein altes Zeugs, das weg kann.
Weder `re` noch `shutil` wird benutzt.
`place` benutzt Du gar nicht, statt dessen hast Du die `destination` nochmal im Code stehen.
Und BASEPATH mit destination verbinden zu wollen, ist an sich schon unlogisch. Natürlich kann man das machen, wenn die destination relativ zum BASEPATH gegeben ist, dann verbindet man Pfadteile mit /.

Code: Alles auswählen

from pathlib import Path

BASEPATH = Path("C:/Users/Startklar/Desktop/Belege")
FILTERS = [
    ("XBIT", "233-00408710"),
]

def main():
    for place, number in FILTERS:
        destination = BASEPATH / place / number
        for sourcefile in BASEPATH.glob(f"*{number}*.pdf"):
            sourcefile.rename(destination / sourcefile.name)

if __name__ == "__main__":
    main()
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Danke Sirius3, mit dem Code funktioniert das Verschieben.

Folgende Verständnisfrage hat sich aber noch ergeben:

Im Ordner XBIT befindet sich ein weiterer Ordner mit der Nummer der zu verschiebenden Datei (233-00408710) und innerhalb dieses Ordners ist noch ein Order mit 2022

Wenn ich den von Dir erhaltenen Code ausführe, wird die Datei nicht nur in den Ordner XBIT sondern auch gleich in den zweiten Ordner mit der Bezeichnung 233-00408710 verschoben. Weshalb ist das so? Ich habe im Filter ja lediglich gesagt, dass die Nummer 233-00408710 in den Ordner XBIT gehört und nicht mehr, oder irre ich mich da?
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

Bebbi hat geschrieben: Donnerstag 5. Mai 2022, 19:56 Wenn ich den von Dir erhaltenen Code ausführe, wird die Datei nicht nur in den Ordner XBIT sondern auch gleich in den zweiten Ordner mit der Bezeichnung 233-00408710 verschoben. Weshalb ist das so? Ich habe im Filter ja lediglich gesagt, dass die Nummer 233-00408710 in den Ordner XBIT gehört und nicht mehr, oder irre ich mich da?
Wie wird denn "destination" zusammengesetzt?
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Super, jetzt habe ich es begriffen. Es funktioniert und ich konnte sogar noch den Ordner mit dem Jahr dranhaengen sogar das passt!

Soweit so gut, aber wie immer kaum ist das eine Problem geloest folgt das naeschste....

Die letzte Verteilung folgt in einen Ordner, welcher nicht ganz genau gleich benannt ist wie der Name in der Datei. Zum Beispiel haben wir bei einer Bestellung folgenden Dateinamen:

20220605_233-00408710_Bestellung

Der Zielordner heisst allerdings nicht Bestellung, sondern Bestellungen. Genau das gleiche gibt es bei Offerte und Offerten.

Ich muesste also in der Lage sein, dem Code zu sagen, dass er nach der ganzen obigen Verteilung, im letzten Schritt Dateien mit dem Namen Bestellung am Ende in den Ordner Bestellungen verschieben soll. Ich nehme an, dass dies ueber einen weiteren Filter geschehen muesste, oder nicht?
Antworten