Datei die ich speichere monatlich umbenennen

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.
Franzel007
User
Beiträge: 13
Registriert: Freitag 12. August 2016, 15:46

Hallo zusammen,

ich habe mir eine Wetterstation mit einem Rasperry Pi gebaut und speichere die gemessenden Daten alle 10 Minuten (py wird über crontab gestartet) in eine csv Datei ab. Das ganze läuft nun seit ca. einem Jahre sehr zuverlässig.
Die jetzige Datei ist nach einem Jahr ist sehr groß geworden.
Nun kam mir die Idee, dass ich ja monatlich eine Datei mit neuem Namen (z.B wetterdaten_01_2018) benutzen könnten.
Da ich dazu noch kein Tutorial gefunden habe, hier nun die Frage ob dies schon jemand realisiert hat und mir den Code zu Verfügung stellen könnte?

Gruß
Franzel
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wo klemmt es denn? Beim Erzeugen des Dateinamens? Beim Erstellen von neuen Dateien? Willst du die bisherige Datei möglicherweise auf Monatsdateien aufteilen?
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Mir fallen da zwei Lösungen ein:

Variante 1: Du erledigst das in deinem Python Skript. Den aktuellen Monat an den Dateinamen anzuhängen ist trivial. Python bringt Datumsoperationen in der Standard Bibliothek mit.

Variante 2: Du erledigst das mit den Mitteln deines Betriebssystems. Unter Linux gibt es dafür z.B. logrotate, das oft schon installiert ist oder leicht nachinstalliert werden kann. Du schreibst dann eine entsprechende Config-Datei, die in /etc/logrotate.d (oder vergleichbar) landet. Der Vorteil hierbei ist, dass du noch diverse weitere Dinge einstellen kannst (max. Dateigröße, Kompression, hooks, ...), die du in deinem Skript, wenn du sie brauchst, selbst programmieren müsstest. Ein bisschen Arbeit ist das aber schon, du zum Beispiel dafür sorgen solltest, dass der Cronjob für dein Skript und die Logratation sich nicht in die Quere kommen, dass eventuelle Spaltennamen auch in die neue Datei geschrieben werden usw. Der Vorteil von Variante 1 ist, dass du eine nahtlose Integration mit deinem Skript hast, was die letztgenannten Punkte einfacher machen kann.
Franzel007
User
Beiträge: 13
Registriert: Freitag 12. August 2016, 15:46

Hallo nochmal,

erstmal geht es wie von euch gut geantwortet um den Weg zum Ziel. Ich bin noch Pythonanfänger und habe gelernt man kann sich bei der Programmierung auch ein Loch in das Knie bohren und eine Stacheldraht durchziehen.

Ich würde es gerne mit dem bereits von mir erstellten Pythonprgramm erledigen.
Das Datum und die Uhrzeit habe ich bereits aufgeteilt in Tage, Monat, Jahr usw in Variablen gelegt und schreibe diese auch in die csv- Datei.
Somit wäre das Jahr und der Monat vorhanden.

Was ich gerne möchte, ist jeweils eine neue Datei am Anfang des Monats automatisch erstellen, und diese dann den ganzen Monat mit den Daten füllen. Im nächsten Monat das ganze vor vorne nur mit einem neuen Dateinamen, der den Monat als Zahl und die Jahreszahl enthält.

Bisher beschreibe ich die Datei mit folgendem Code

Code: Alles auswählen

#Ausgabe in Datei schreiben
try:
    d = open("/home/shares/pi/wetterhaus_2018_python3_test.csv","a")
    
except:
    print("Dateizugriff auf lokale Datei /home/shares/pi nicht erfolgreich")
    sys.exit(0)

d.write (time.strftime("%d/%m/%Y") + ";" + time.strftime("%H:%M:%S") + ";" + str(Luftfeuchte).replace(".",",")
         + ";" + str(Temperatur).replace(".",",") + ";" + str(Temperatur2).replace(".",",")
         + ";" + str(Druck).replace(".",",") + ";" + str(Hoehe).replace(".",",") + ";" + str(ad1).replace(".",",")
         + ";" + str(ad2).replace(".",",") + ";" + str(ad3).replace(".",",") + ";" + str(ad4).replace(".",",")
         + ";" + str(ad5).replace(".",",") + ";" + str(ad6).replace(".",",") + ";" + str(ad7).replace(".",",")
         + ";" + str(ad8).replace(".",",") + ";" + str(ad9).replace(".",",") + ";" + str(ad10).replace(".",",")
         + ";" + str(ad11).replace(".",",") + ";" + str(ad12).replace(".",",") + ";" + str(Lichtlux1).replace(".",",")
         + ";" + str(Lichtlux2).replace(".",",") + "\n")
                                                         
d.close()

Gruß
Thomas
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du baust doch schon strings zusammen. Auf etwas grausliche Weise mit + statt format zu benuzten, aber sei’s drum. Was hindert dich denn daran den Dateinamen genauso zu bauen?

Code: Alles auswählen

time.strftime(“%Y-%m.csv”)
zb als Start, zusammen mit os.path.join für den vollen Pfad.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Franzel007: Wenn Du Dir, wie von __deets__ gezeigt, die Dateinamen selbst erstellst, dann kannst Du vor dem öffnen der Datei prüfen, ob es die Dateie schon gibt. Falls ja, dann füge weitere Daten an, andernfalls erstelle eine neue Datei. Das ist beides sogar recht einfach und Du bist fast am Ziel.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

@kbr warum loest das append im file-mode das er schon verwendet das nicht schon von alleine?
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Ich bin noch Pythonanfänger und habe gelernt man kann sich bei der Programmierung auch ein Loch in das Knie bohren und eine Stacheldraht durchziehen.
Programmieranfänger neigen allerdings manchmal dazu, Lösungen als einfacher zu betrachten, die ausschließlich auf ihrem aktuellen Kenntnisstand operieren. Dabei sind gerade diese Lösungen öfters mal die wesentlich komplizierteren. Beispielsweise könntest du für das Schreiben der CSV-Datei auf das entsprechende Modul zurückgreifen, statt selbst CSV zu erzeugen.

Hier jedenfalls mal ein Beispiel, wie man es meiner Meinung nach lösen könnte:

Code: Alles auswählen

#!/usr/bin/env python3
import pathlib
import csv
from datetime import datetime
from random import randint

TEMPLATE = '/tmp/mylog_{year}-{month}.csv'

def main():
    now = datetime.now()
    path = pathlib.Path(TEMPLATE.format(year=now.year, month=now.month))
    fieldnames = ('timestamp', 'temperature', 'humidity')
    if not path.exists():
        with path.open('w') as fh:
            writer = csv.writer(fh)
            writer.writerow(fieldnames)
    with path.open('a') as fh:
        writer = csv.writer(fh)
        data = [datetime.now().timestamp(), randint(-10, 50), randint(1, 100)]
        writer.writerow(data)


if __name__ == '__main__':
    main()
(Es kann sein, dass du pathlib durch entsprechende Funktionalität aus os.path ersetzen musst.)
Zuletzt geändert von nezzcarth am Sonntag 10. Dezember 2017, 13:54, insgesamt 1-mal geändert.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@__deets__: Klar, das geht natürlich – soweit hatte ich gar nicht gelesen.
Franzel007
User
Beiträge: 13
Registriert: Freitag 12. August 2016, 15:46

Hallo und nochmals danke,

ich habe mir eure Tips angeschaut und mich für diesen (ich weiß Anfänger- Python) Weg entschieden.

Code: Alles auswählen

#!/usr/bin/python3
#-*- coding: iso-8859-1 -*-

#Test Filename mit Datum erstellen in Python3

#Module laden
import sys
import time

#Datum und Uhrzeit
lt = time.localtime()
jahr, monat, tag = lt[0:3]
stunde, minute, sekunde = lt[3:6]

#Ausgabe Datum und Zeit
print ("Datum                      :{0:02d}/{1:02d}/{2:04d}".format(tag, monat, jahr))
print ("Uhrzeit                    :{0:02d}:{1:02d}:{2:02d}".format(stunde, minute, sekunde))


#Filename definieren
filename = (str(jahr) + str("_") + str(monat) + str("_") + str("wetterhauesle"))

print ("Filename heisst: ", filename)


#Ausgabe in Datei schreiben
try:
    d = open("/home/shares/pi/"+filename,"a")
    
except:
    print("Dateizugriff auf lokale Datei /home/shares/pi nicht erfolgreich")
    sys.exit(0)

d.write ("Hallo Test")
                                                         
d.close()
Gruß
Franzel
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Franzel007: warum verwendest Du .format bei print, stückelst aber dann den Dateinamen mit str und + zusammen? Du weißt doch wie es besser geht. »str« auf einen literalen String anzuwenden, ist doppelt komisch. Niemals nackte excepts benutzen, denn Du fängst viel mehr Fehler ab, als Du denkst. Hier machst Du nicht einmal was sinnvolles mit dem Fehler. Pfade setzt man mit os.path.join zusammen und Dateien öffnet man mit dem with-Statement:

Code: Alles auswählen

import os
from datetime import datetime

#Datum und Uhrzeit
now = datetime.now()

#Ausgabe Datum und Zeit
print("Datum                      :{:d.m.Y}".format(now))
print("Uhrzeit                    :{:H:M:S}".format(now))

filename = "{:Y_m}_wetterhauesle".format(now)
print("Filename heisst: ", filename)

with open(os.path.join("/home/shares/pi", filename), "a") as d:
    d.write("Hallo Test")
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: Wenn Du an os.path.join sowas wie "/home/shares/pi" übergibst, dann kannst Du den Pfad auch getrost mit + zusammenbauen ... :wink:
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: was ist an dem Pfad `/home/shares/pi` falsch?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: Daran ist nichts falsch in dem Sinne, dass es mit den heute am meisten verbreiteten Betriebssystemen funktioniert, aber der slash ist ein Betriebssystem abhängiger Separator, so dass

Code: Alles auswählen

os.path.join('/home', 'share', 'pi', filename)
konsequent wäre.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: was ist mit `/home`? Solche Strings gehören nicht in den Code, sondern als Konstanten an den Anfang, so dass sie je nach System schnell geändert werden können:

Code: Alles auswählen

import os
from datetime import datetime

HOME_PATH = "/home/shares/pi"
 
#Datum und Uhrzeit
now = datetime.now()
 
#Ausgabe Datum und Zeit
print("Datum                      :{:d.m.Y}".format(now))
print("Uhrzeit                    :{:H:M:S}".format(now))
 
filename = "{:Y_m}_wetterhauesle".format(now)
print("Filename heisst: ", filename)
 
with open(os.path.join(HOME_PATH, filename), "a") as d:
    d.write("Hallo Test")
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: Es ging um os.path.join, nicht um Konstante.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: es geht darum, dass man absolute Pfade nicht systemübergreifend festlegen kann, will man also solch ein Programm möglichst einfach anpassbar machen, verstreut man am besten nicht alle Änderungen über den gesamten Code, sondern sammelt sie am Anfang.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: Mir ging es darum, dass der Vorteil der Nutzung von os.path.join, nämlich die automatische Nutzung os-spezifischer Separatoren, verlorengeht, sobald auch nur einmal davon abgewichen wird, so wie Du es getan hast.
Deine Anmerkungen sind zwar korrekt, aber ich habe den Eindruck, dass Du Dich auf den führenden Slash bei '/home' kaprizieren möchtest. Ja, den hätte ich weglassen können, das lässt sich anders angehen.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@kbr:
Der Pfad für benutzerspezifische Dateien ist unter Windows ein ganz anderer als unter Linux-Systemen. Trotzdem ist es vorteilhaft, os.path.join() einzusetzen, wenn vorher ein bestimmter Pfad festgelegt wurde und man da die gewünschte Datei ablegt (/home/whatever/ <-> C:\Whatever\).

IMHO verstehst du hier den Sinn von os.path.join() falsch. Es geht ja nicht darum, jeden erdenklichen Pfad quasi nachträglich in eine "join()-Version" umschreiben zu müssen. Man will einfach an Stellen, wo tatsächlich noch etwas zusammengesetzt werden muss, eine plattformübergreifende Lösung haben.

Und das von dir bemängelte os.path.join("/home/shares/pi", filename) mag erstmal unnötig erscheinen. Im tatsächlichen Code jedoch schreibt man das vielleicht jetzt oder später als Konstante (wie ja schon gesagt wurde). Und dann ist der Weg über join() durchaus sinnvoll. Ob man es daher in weiser Voraussicht gleich so schreibt, ist Geschmackssache. Falsch ist es jedoch nicht.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

snafu hat geschrieben:Man will einfach an Stellen, wo tatsächlich noch etwas zusammengesetzt werden muss, eine plattformübergreifende Lösung haben.
So verstehe ich es auch. Nur was zuvor zusammengesetzt wurde, sollte dann auch plattformübergreifend funktionieren, sonst ergibt sich kein Nutzen. Falls ich da etwas falsch sehe, korrigiere mich bitte.
Antworten