Index.html mit Übersicht von Ordner und Dateien erstellen

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
ernestovaya
User
Beiträge: 7
Registriert: Dienstag 16. Oktober 2012, 13:47

Hallo,

ich schreibe innerhalb eines Verzeichnisses für jeden Ordner eine index.html. In jeder index.html sollen die Unterordner, sowie alle anderen .htmls geschrieben werden. Sprich befindet sich im Ordner "1" die Datei "bla.html" sowie der Ordner "2" sollen diese in die index.html von "1" geschrieben werden. Soweit so gut. Wenn sich nun aber in einem Unterordner (hier: "2") keine anderen htmls oder keine weiteren Ordner befinden, soll dieser auch nicht in die index.html von "1" geschrieben werden. Und genau hier ist mein Problem. Eine index.html für "2" wird zwar nicht geschrieben, aber der Ordner erscheint in der index.html von "1".

Hier der Code, den ich ein wenig verschlankt habe.

Code: Alles auswählen

rlist=[]
i=0
for r,d,f in os.walk(Z:):
    root= r.replace('Z:', 'H:')
    root=root.replace('\\','/')
    files = []
    for files in f:
        m=root+"/"+files
        if m.endswith('.html') or os.path.isdir(root):
            rlist.append(root)
            a=list(set(rlist))
            a.sort()
            (drive, tail) = os.path.splitdrive(root)
            tail = tail+'/'
            index = open(''+root+'/index.html', 'w')
            index.write('<title>'+r+'</title>\n')
            index.write('<body>\n')
            content = os.walk(''+a+'').next()[1]
            for row in content:
                index.write('<a href="'+row+'/index.html"> '+row+'</a>\n')
                index.write('<br>\n')
            for g, files in enumerate(f):
                if files.endswith('.dta'):
                    files = files.replace('.dta', '.html')
                    index = open(''+root+'/index.html', 'a')
                    index.write('<a href="'+tail+''+files+'">'+f[g]+'</a>\n')
                    index.write('<br>\n')
                    index.write('</body>\n')      
            index.close()
Der Fehler liegt denke ich bei content. os.walk funktioniert bei Listen nicht, wandele ich aber die Listen in Strings um, bricht er auf der nächsten Ebene ab.

Über Hilfe wäre ich sehr dankbar!
BlackJack

@ernestovaya: Wenn *das* schon einer verschlankte Version ist, möchte ich nicht das original sehen. Teil den Code sinnvoll auf Funktionen auf, mit vernünftigen und *passenden* Namen an denen man erkennen kann was der Wert dahinter bedeutet. *Einen* Dateinamen `files` zu nennen, oder `r`, `d`, `f`, `a`, `m`, und `g` machen das ganze sehr schwer nachvollziehbar. Den gleichen Namen in verschachtelten Schleifen mehrfach als Laufvariable zu verwenden ist auch keine gute Idee.

Was denkst Du eigentlich was das addieren einer leeren Zeichenkette zu einer anderen Zeichenkette für einen Effekt hat? Warum machst Du das mehrfach in dem Quelltext?

Die ganze Schleifenlogik ist ziemlich daneben. `rlist` wird immer länger und wird bei jeder Datei in dem Durchlauf durch eine beliebig tiefe Verzeichnishierarchie auf welche die Kriterien zutreffen komplett durchlaufen.

Für jeden Treffer bei den gefundenen Dateinamen werden wieder alle Dateinamen durchlaufen und für jede dieser Dateien wird die ``index.html`` aufs neue geöffnet und nicht wieder geschlossen(!). Für *jede* dieser Dateien wird ein schliessendes <body>-Tag in die Datei geschrieben — das darf aber nur einmal in einer HTML-Datei vorkommen.

Beim Aufteilen in Funktionen sollte man die Eingabe, also das lesen der Informationen aus dem Dateisystem, auch von der Ausgabe trennen. Wenn das sauber getrennt ist, lässt sich auch einfacher halbwegs gültiger HTML-Quelltext generieren. Wobei ich dafür eine Bibliothek nehmen würde, damit man sich nicht selber um Zeichen kümmern muss, die zwar in Dateinamen gültig sind, in HTML aber Probleme bereiten können.

Speziell zu `content`: `a` ist eine Liste. Die kann man weder zu einer Zeichenkette mit ``+`` hinzufügen, noch macht das an der Stelle irgendeinen Sinn, wenn man sich anschaut was `os.walk()` als Argument erwartet. Da `rlist` Verzeichnisnamen über die gesamte Verzeichnishierarchie ansammelt, kann ich mir auch nicht wirklich vorstellen was an der Stelle da überhaupt *tatsächlich* passieren soll.

Erst mit `endswith()` auf eine Endung testen und falls Vorhanden mit `replace()` und dieser Endung weitermachen ist nicht robust. `replace()` ersetzt *alle* vorkommen, Du willst doch aber nur die Endung ersetzen.
ernestovaya
User
Beiträge: 7
Registriert: Dienstag 16. Oktober 2012, 13:47

@Black jack: vielen Dank für die schnelle antwort.
Bei rlist bin ich mir dessen schon bewusst. Allerdings war mir nicht klar, wie ich dieses Problem umgehen könnte. Ich musste ja das "for file_html in f" einführen um überhaupt nach dateinamen filtern zu können oder sehe ich das falsch?

Also es soll die html ja auch nach einem Treffer bei den Dateien bzw Ordner nicht wieder schließen, sondern erst alle relevanten reinschreiben und danach schließen. Dachte eigentlich dass ich dann die index.html am Ende der Schleife ja auch mit index.close() schließe. Stimmt <body> muss mir da irgendwie reingerutscht sein. Danke!

Das mit replace leuchtet ebenfalls ein, jedoch bin ich davon ausgegangen, dass wenn ich einen "." davor setze, dass dies dadurch eindeutig wird, auch wenn nicht wirklich pythonic. Wie könnte man dies noch lösen? In dem man den Dateinamen von der extension mit split trennt und diese ersetzt? Oder wäre das der gleiche Effekt?

Naja "a" enthält eben alle relevanten Unterordner die entweder eine relevante Datei und/oder einen Ordner beherbergt. Und diese Ordner sollten dann auf der index.html von "1" geschrieben werden. Und eben dies funktioniert ja auch nicht, jedoch finde ich keine Lösung die auf Listen zugreift und äquivalent zu *.next()[1] ist, damit in dieser Schleife nur die Ordner notiert werden.
BlackJack

@ernestovaya: Mit dem ``index.close()`` schliesst Du *eines* der vielen Dateiobjekte die Du in der Schleife öffnest, nämlich das letzte welches geöffnet wurde.

Man könnte den Dateinamen von der Endung trennen, oder einfach alle Zeichen ausser der Endung mittels „slicing” ermitteln und dann die neue Endung anhängen. Ungefähr so:

Code: Alles auswählen

if filename.endswith(DTA_EXTENSION):
    html_filename = filename[:-len(DTA_EXTENSION)] + '.html'
Da `a` von `rlist` abhängt, und das ziemlich unsinnig befüllt und benutzt wird, verstehe ich auch `a` nicht. Und auch immer noch nicht wie Du mit einer *Liste* `os.walk()` aufrufen willst, weil diese Funktion damit einfach mal nichts anfangen kann.

Wie gesagt: Teil das ganze in vernünftige, in sich geschlossene Teilschritte und stecke die in Funktionen. Am besten mit Trennung von ermitteln der Daten und schreiben der HTML-Dateien. Und mit verständlichen Namen für die Funktionen und Variablen.

Wenn man Daten aus einem Verzeichnis in der Verarbeitung des darüber liegenden Verzeichnisses benötigt, wäre es eventuell auch sinnvoll sich eine eigene rekursive Funktion zu schreiben, statt `os.walk()` zu verwenden, was ja aus Sicht des Aufrufers die Rekursion versteckt. Bei `os.walk()` muss man sonst bei jeder Ebene selbst schon mal in die darunter liegenden Verzeichnisse schauen, die danach dann noch einmal von `os.walk()` besucht werden.
Antworten