Hi,
ich dachte eigentlich, es wäre einfacher, aber meine Aufgabe hat einige Stolpersteine.
Ich habe folgende Ausgangssituation: ich habe auf mehreren PC identische oder zumindest ähnliche Verzeichnisstrukturen mit Bildern im BMP Format. Die synchronisiere ich auf meinen lokalen PC. Jeder Remote PC muss in ein eigenes Verzeichnis gespeichert werden.
Jetzt möchte ich die Bilder rekursiv nach PNG konvertieren. Das ist noch nicht das eigentliche Problem. Das Problem ist, dass die Verzeichnisstruktur erhalten bleiben soll und die Unterverzeichnisse der Remote PC in ein gemeinsames Verzeichnis zusammengefasst werden. Ich Versuche ein Beispiel.
PC1 hat die Unterverzeichnisse foo1, foo2 und foo3. Jedes dieser Verzeichnisse hat weitere Unterverzeichnisse.
PC2 hat die Unterverzeichnisse foo1, foo2 und foo4 usw
Ich möchte jetzt alle PNG Bilder, die in den foo1 Ordnern gespeichert sind, in einen gemeinsamen foo1 Ordner auf dem lokalen PC konvertieren, egal von welchem Remote PC.
Auf dem Lokalen PC soll es also jeweils nur ein foo1, foo2, foo3 und foo4 Verzeichnis geben, in denen die Bilder von allen Remote PCs gespeichert sind.
Last but not least sollen die original Bilder gelöscht und mit leeren Dateien mit gleichem Dateinamen ersetzt werden, um den Speicherplatz frei zu geben, aber eine weitere Synchronisation zu ermöglichen.
Durch die Verzeichnisse zu wandern und Bilder konvertieren bekomme ich hin. Was mir Probleme macht ist das abspeichern am richtigen Zielort. Klingt eigentlich banal, aber verknotet mir gerade das Hirn. Vermutlich ist es total simpel, aber ich komme nicht drauf.
Wie kann ich den Knoten lösen?
Ach ja, ich möchte das in pure Python machen damit es sowohl unter Windows als auch Linux funktioniert.
Schönen Sonntag
Batch conversation von BMP zu PNG mit Extras
Das Problem löst sich, wenn du den Umstand weg lässt, dass es mehrere Clients sind. Es ändert sich ja nur das Basisverzeichnis für die Quelldateien. Die anderen Pfade sind relativ zu diesem. Sowohl zum Basisverzeichnis der Quelle als auch des Ziels.
Das ist klar. Aber ich stehe wie gesagt gerade komplett auf dem Schlauch. Grundsätzliche Frage: was eignet sich besser? os.walk, glob oder etwas anderes? Und wie erstelle ich nicht vorhandene Verzeichnisse?sparrow hat geschrieben: ↑Sonntag 16. Januar 2022, 08:17 Das Problem löst sich, wenn du den Umstand weg lässt, dass es mehrere Clients sind. Es ändert sich ja nur das Basisverzeichnis für die Quelldateien. Die anderen Pfade sind relativ zu diesem. Sowohl zum Basisverzeichnis der Quelle als auch des Ziels.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Nach einer Tasse Kaffee hat sich der Knoten etwas gelöst, aber mir ist ein anderes Problem aufgefallen, das mein Vorhaben gerade generell sabotiert.
Trotzdem noch einen schönen Sonntag
Trotzdem noch einen schönen Sonntag
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Der Vollständigkeit halber hier mal meine Lösung. Die Variablennamen müssten eventuell noch etwas überarbeitet werden
Code: Alles auswählen
import os
from PIL import Image
import glob
import re
images = glob.glob('PC?/**/*.bmp', recursive=True)
for img in images:
# Skip if file is too small
if os.path.getsize(img) < 10:
continue
file = os.path.split(img)
new_file = (re.sub(r"PC\d+", "PNG",
file[0]), file[1].replace(".bmp", ".png"))
# Skip if file already exists
if os.path.exists(os.path.join(new_file[0], new_file[1])):
continue
# Create dir if not exists
os.makedirs(new_file[0], exist_ok=True)
# Convert BMP to PNG and save in new dir
Image.open(img).save(os.path.join(new_file[0], new_file[1]))
print(os.path.join(new_file[0], new_file[1]))
# Remove original file and replace with empty file
os.remove(img)
os.mknod(img)
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Statt `os` und `glob` benutzt man `pathlib.Path`. Und auf pfade geht man auch nicht mit Stringoperationen los, wie `re`oder `replace`, sondern nutzt das, was pathlib.Path so bietet.
Man setzt auch nicht an vier verschiedenen Stellen den Gesamtdateinamen zusammen, sondern speichert das Ergebnis einmal in einer Variable.
Man setzt auch nicht an vier verschiedenen Stellen den Gesamtdateinamen zusammen, sondern speichert das Ergebnis einmal in einer Variable.
Code: Alles auswählen
from pathlib import Path
from PIL import Image
INPUT_PATH = Path('.')
OUTPUT_PATH = Path('PNG')
for pc_path in INPUT_PATH.glob('PC?'):
for imagefilename in pc_path.glob('**/*.bmp'):
# Skip if file is too small
if imagefilename.stat().st_size < 10:
continue
relative_imagefilename = imagefilename.relative_to(pc_path)
new_imagefilename = (OUTPUT_PATH / relative_imagefilename).with_suffix('.png')
# Skip if file already exists
if new_imagefilename.exists():
continue
new_imagefilename.parent.mkdir(parents=True, exist_ok=True)
image = Image.open(imagefilename)
image.save(new_imagefilename)
print(new_imagefilename)
# Remove original file and replace with empty file
imagefilename.write_bytes(b"")
Das ich mehrfach joine weiß ich. Werde ich bei Gelegenheit ändern. pathlib schaue ich mir auch einmal an, danke.Sirius3 hat geschrieben: ↑Sonntag 16. Januar 2022, 11:30 Statt `os` und `glob` benutzt man `pathlib.Path`. Und auf pfade geht man auch nicht mit Stringoperationen los, wie `re`oder `replace`, sondern nutzt das, was pathlib.Path so bietet.
Man setzt auch nicht an vier verschiedenen Stellen den Gesamtdateinamen zusammen, sondern speichert das Ergebnis einmal in einer Variable.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Nochmal danke für die Überarbeitung. Ich hab noch etwas eingefügt, um ältere Dateien komplett zu löschen.
In dem Dateinamen sind alle Infos enthalten und mit "_" getrennt. Das Datum steht im Format yyyymmdd an Position [3]. Da beim überschreiben der Original Datei auch das Datum geändert wird kann ich das nicht mehr verwenden. Deshalb hab ich das so gelöst. Hat da noch jemand einen Verbesserungsvorschlag?
Code: Alles auswählen
fname = imagefilename.name
file_date = fname.split("_")[3]
year, month, day = file_date[:4], file_date[4:6], file_date[6:]
now = datetime.datetime.now()
then = datetime.datetime(int(year), int(month), int(day))
age = (now - then).days
if age > 10 and imagefilename.stat().st_size < 10:
imagefilename.unlink()
print(fname + " deleted")
continue
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Zum Parsen vom Datum gibt es strptime:
Code: Alles auswählen
file_date = imagefilename.name.split('_')[3]
then = datetime.datetime.strptime(file_date, '%Y%m%d')
Super, danke. Sieht etwas eleganter aus und spart nochmal zwei Zeilen. Das Script tut was es soll. Da kann ich morgen in der Realtest gehen.Sirius3 hat geschrieben: ↑Sonntag 16. Januar 2022, 14:22 Zum Parsen vom Datum gibt es strptime:Code: Alles auswählen
file_date = imagefilename.name.split('_')[3] then = datetime.datetime.strptime(file_date, '%Y%m%d')
Einziges Problem ist, dass die Dateien auf den Remote Rechnern nach einer Weile gelöscht werden und ich darf keine alten und erst recht keine leeren Dateien zurück synchronisieren. Die Synchronisation läuft immer in beide Richtungen, es sei denn ich kann das irgendwie verhindern.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Ich hab noch eine Frage zu pathlib (bin gerade am Handy, deshalb kein c&p vom Code). Ich möchte alle PNG Dateien in einem Verzeichnis mit OpenCV bearbeiten.
Ich lege mit Path() einen relativen Pfad an, hole mir p.glob("*.PNG") alle Dateien und laufe mit einer for loop über die Liste. So weit, so gut.
Einziges Problem: ich muss mit str() den String aus dem Objekt holen, damit ich die Datei mit cvw.imread() laden kann. Ist das der "offizielle" weg oder gibt es da eine Methode, die einen String liefert? resolve() und absolute() liefern ja auch nur Objekte.
Übersehe ich da was?
Ich lege mit Path() einen relativen Pfad an, hole mir p.glob("*.PNG") alle Dateien und laufe mit einer for loop über die Liste. So weit, so gut.
Einziges Problem: ich muss mit str() den String aus dem Objekt holen, damit ich die Datei mit cvw.imread() laden kann. Ist das der "offizielle" weg oder gibt es da eine Methode, die einen String liefert? resolve() und absolute() liefern ja auch nur Objekte.
Übersehe ich da was?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol: