7z t + datei (bei großen Dateien -> schwarzes Fenster)

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
baitu
User
Beiträge: 4
Registriert: Montag 6. Mai 2013, 19:28

Hallo!


Ich habe mir ein Script gebastelt, welches eine Datei dahingehend testen soll, ob sie überhaupt mit 7zip entpackbar ist. Sinnvoll erschien mir hier der "t" Schalter von 7zip.

Code: Alles auswählen

import os, fnmatch, sys, subprocess, re, shlex


def ztest (datei):
    args = '7z.exe t ' + datei
    p=subprocess.Popen(shlex.split(args),shell=False,stdout=subprocess.PIPE)
    p.wait()
    returnvalue=p.returncode
    if returnvalue == 0:
        test = subprocess.check_output(args, shell=True)
        regexp = re.compile(r'.rsrc|.data')
        if regexp.search(test) is not None:
            return 55
        else:
            return 0
    elif returnvalue == 1:
        return 1
    elif returnvalue == 2:
        return 2
    elif returnvalue == 7:
        return 7
    elif returnvalue == 8:
        return 8
    elif returnvalue == 255:
        return 255
Die Return-Werte sind von 7zip (bis auf die 55). Wenn ich innerhalb des Scriptes eine Datei testen lasse, klappt das wunderbar. Wenn ich jedoch aus einem anderen Skript heraus eine etwas größere Datei testen lassen möchte (z.B.: 314.22-notebook-win8-win7-32bit-international-whql.exe mit 167 MB), geht zwar das "schwarze Fenster" auf, aber es passiert nichts.
Bei kleineren Dateien (z.B.: sqlite-analyzer-win32-x86-3071600.zip mit 652 KB) bekomme ich den passenden Rückgabe-Wert.
Ab ca. 1 MB große Dateien geht nichts mehr...

Vielen Dank im Voraus!
Ich nutze python-2.7.4.amd64.msi unter Windows 7 x64 Professional.
BlackJack

@baitu: Du sagst beim ersten Aufruf, dass die Ausgabe des externen Prozesses mit Deinem verbunden werden soll, aber dann liesst Du die überhaupt nicht. Sobald also der Pufferspeicher zwischen den beiden Prozessen voll ist, wartet 7z darauf das Du endlich mal die Ausgaben liest, und Du wartest darauf, das 7z mal zum Ende kommt. Und damit warten beide Prozesse bis in alle Ewigkeit. Oder bis man sie halt abbricht.

Da sind einige komische Sachen in der Funktion. Zum Beispiel dass Du erst eine Kommandozeile als Zeichenkette aufbaust, um die dann mit `shlex.split()` wieder zu zerlegen. Statt gleich eine Liste zu erstellen, das dann unnötige `shlex.split()` wegzulassen und bei dem `shell`-Argument bitte immer `False` zu übergeben. Das funktioniert mit ``shell=True`` nicht mit allen Dateinamen.

Es ist ein wenig ungünstig 7z das Archiv *zweimal* entpacken zu lassen. Gerade bei grösseren Archiven macht sich diese unnötige Arbeit in der Laufzeit bemerkbar.

`re.compile()` macht nicht wirklich Sinn wenn man den kompilierten regulären Ausdruck dann nur *einmal* verwendet.

Was hast Du Dir bei den ganzen ``elif``\s gedacht? Da kann man doch ganz einfach `returnvalue` zurück geben. Und was passiert wenn keines der ``elif``\s zutrifft? Was soll dann zurückgegeben werden?

Statt solcher „magischen” Zahlen würde man vielleicht aus eher mit Ausnahmen arbeiten. Oder zumindest die Zahlen als Konstanten definieren, damit man beim lesen des Quelltextes schon versteht, was dort passiert und nicht erst in der 7z-Dokumentation nachlesen muss.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo baitu,
das was Du machst, macht für mich nicht wirklich Sinn.
- das Leerzeichen zwischen ztest und ( gehört weg.
- warum baust Du einen String erst zusammen um in danach wieder zu splitten? »Popen« bekommt am besten als erstes Argument gleich eine Liste. Das anhängen von »datei« an den String führt zu Problemen, falls Sonderzeichen vorkommen.
- »wait« liefert schon den »returncode« zurück.
- warum startest Du dann mit »check_output« nochmals das selbe Programm (diesmal über die Shell, was an sich schon schlecht ist)? Wenn Du den Output haben willst, dann lies in doch von »p.stdout«.
- Beim regulären Ausdruck meinst Du wahrscheinlich mit ».« nicht „beliebiges Zeichen“ sonder tatsächlich „.“.
- Die lange elif-Kette könnte man auch mit »return returnvalue« abkürzen.
- Wenn nichts zutrifft wird ein implizites »None« zurückgeliefert, das sollte nicht sein.

Ich komme auf

Code: Alles auswählen

def ztest(datei):
    p=subprocess.Popen(['7z.exe', 't', datei], stdout=subprocess.PIPE)
    text = p.stdout.read()
    returnvalue = p.wait()
    return 55 if returnvalue==0 and re.search(r'\.rsrc|\.data', text) else returnvalue
Ob Deine Probleme von der komischen Programmierung herrühren, weiß ich aber auch nicht.
baitu
User
Beiträge: 4
Registriert: Montag 6. Mai 2013, 19:28

Danke schön erst einmal. Danke auch dafür, dass ihr mir so ausführlich geantwortet habt! Werde mir das mal in Ruhe anschauen.
P.S.: ich habe genau das gemacht, worauf hier hingewiesen wird.
Eigentlich wollte ich nur eine Routine haben, mit der man von Dateien Hashwerte erzeugen kann. Diese wollte ich als .exe kompilieren und sie in AutoIt weiternutzen.
Dann habe ich mir aber gedacht, dass ich es mal mit Python versuchen könnte.
Bei meiner Suche nach 7zip und Kommandozeile habe ich irgendwo einen Teil herauskopiert.

Bezüglich der elif: ich muss mich erst an das Einrücken gewöhnen. Ich wollte zunächst eine Schleife in einer Schleife laufen lassen, allerdings bekam ich immer Fehlermeldungen.
Das obige Skript ist einfach zusammengewürfelt.

Daher noch mal vielen Dank für eure Antworten!
Antworten