file.read() im bytemode -Zeichen nicht erkannt

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
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

Ich bin auch neu hier (und in Python, zZt. 3.6)!
Hab aber schon vieles geklaut ohne Anmeldung.Danke !

Problem:
ich habe eine kleine Konsolenanwendung, die eine Bytefolge analysiert, das funktioniert super !

Code: Alles auswählen

file1 = (open('Datei', 'rb')
data = file1.read(1)
if data == b'&':
...
jetzt hab ich das in einen thread gebastelt der mit queue und tkinter zusammenarbeitet. Der Ablauf funktioniert auch super, aber:
die Abfrage:

Code: Alles auswählen

data = file1.read(1)
if data == b'&':

wird komplett ignoriert, obwohl identisch zur Konsole
ich hab auch mit if data == b'\x26':
und if data ==chr(38): experimentiert - das letzte geht garnicht (auch Konsole nicht)
die Zeichen sind nur Beispiel!
Hat da jemand eine Idee ?
Danke für die Mühe
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein, denn keiner kann sehen, was in data steht. Was gibt denn print(data) vor der if-Anweisung aus? Wie sieht der ganze Code aus? Ist die Datei frisch geoeffnet, ist der Dateizeiger ggf. schon am Ende?
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

Hallo __deets__

Code: Alles auswählen

s = (file1.read())
lae = file1.tell()
file1.seek(0)
print (datei1, ' hat ', lae , 'bytes')

a = 0
b = 0
c = 0
addr = [1]
laenge = [1]
while b < lae:
    data = file1.read(1)
    if data == b'$':
        data = file1.read(1)
        print(a,b,data)
        b = b+1
        if data == b'$':
                data = file1.read(1)
                b = b+1
                if data == b'$':
                        data = file1.read(1)
                        b = b+1
                        if data == b'$':
                                data = file1.read(1)
                                b = b+1
                                if data == b'$':
                                    '''Datum = file1.read(11)
                                    Zeit = file1.read(10)
                                    Nummer = file1.read(8)'''
                                    a = a+1
                                    addr.append (b-4)                                  
                                    laenge.append (addr[a] - addr[a-1])
                                    
                                    if not data:
                                        break
    b = b+1
a_ges = a    
print ( 'Anzahl Datensätze: ' , str(a), 'Länge(byte) gesamt:  ', str(b))
ok, ich hab das zum testen mit haufenweise prints versehen -(eine ist noch übrig, nach der ersten If- Abfrage) daher habe ich die Sicherheit, daß
1. die richtigen bytes in data stehen und
2. die if- Abfragen ignoriert werden, da wird nix gedruckt...
durch das letzte b= b+1 weiß ich, daß alle bytes in file1 abgefragt werden; die bytefolge $$$$$ ist im Testfile mindestens 6 mal vorhanden, so daß in der Konsole a = 6 und b = 649 rauskommmt... beim gleichen code als Funktion aber nicht

die fünf IF- Abfragen sind unschön, das weiß ich - mit der gesamten Zeichenfolge hats aber in der Konsole nur gelegentlich funktioniert...so, wie oben immer...
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich sehe da weder tkinter, noch einen Thread. Und in *dem* Code ist doch der Fehler aufgetreten. Nicht in deiner Konsolen-Variante, die du hier zeigst?

Ausserdem ist der Code wirklich ziemlich grausam und schwer verstaendlich. Wie sieht denn der Inhalt deiner Datei aus, und was willst du da genau berechnen? Das geht in Python unter Garantie besser, als so kompliziert Byte-weise einzulesen.
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Vor allem wird die Datei ja ganz am Anfang komplett in `s` eingelesen, was das nachfolgende Byteweise lesen völlig sinnfrei macht.

Wenn man das nicht komplett in den Speicher lesen möchte, aber trotzdem wie eine `bytes`-Objekt behandeln möchte, wäre vielleicht auch ein Blick auf das `mmap`-Modul interessant.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

Danke zunächst für die schnelle Reaktion...
s wird später gebraucht... dort hole ich erstmal nur die Dateilänge (lae) und setze dann den Zeiger auf Anfang
ich brauche da oben nur die Anfangspositionen der interessanten sequenzen ( wird im array addr[] gepeichert); diese beginnen immer mit einer Zeichenfolge, wie eben '$$$$$' oder auch anderen. Der Dateianfang kommt aus einem logger und kann irgendwo zwischendrin liegen.
Und ich brauche die Länge der sequenz.
das ganze muß byteweise erfolgen, da ASCIIs, 4byte floats und anderes Gerümpel wild gemischt vorliegen und auseinandergepflückt werden müssen. Es kommen also auch alle möglichen Zeichen (\x00 bis\xff) vor und die sollen weder umcodiert noch als Steuerzeichen interpretiert werden
der code mit tkinter und thread ist inzwischen ziemlich lang, muß ich erstmal auf das wesentliche kürzen;
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

...aber die Idee (__blackjack__) ist schonmal gut, diese Analysen in s zu machen und nicht in der Datei...
Ich bin hochgradig prozedural vorbelastet (PIC in Assembler und 'C'), da muß man erstmal über den eigene Schatten...
mein erster Computerbefehl war C3 FF 0F (unbedingter Sprung auf 0FFF; Z80 im Jahre 1978...); der war nur dazu da, das Ding in eine Endlosschleife zu jagen, um am Oszi was messen zu können
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

ok, selbst schuld ... ich hab alles dringelassen...

Code: Alles auswählen

import tkinter as tk
from tkinter import filedialog as fd
from queue import Queue
from threading import Thread, Event
from random import random
from time import sleep
import datetime as dt
import os, serial

global data
data = {'Dateipfad':'', 'Dateiname':'', 'Dateilaenge': 0, 'Startzeit':'', 'Start': False, }
data2 = {}

def main():
    my_queue = Queue()
    my_queue1 = Queue()
    my_event = Event()
    my_event1 = Event()
    my_thread = Thread(target=generate_data, args=(my_queue, my_event, ))
    my_thread.start()
    my_thread2 = Thread(target=seriell_in, args=(my_queue1, my_event, ))
    my_thread2.start()
    root = tk.Tk()
    app = Application(my_queue, my_queue1, my_event, master=root)
    app.master.title('Dateianalyse')
    app.mainloop()

    
def seriell_in(my_queue1, event):
    global data
    while not event.is_set():
        if data['Start'] == False:
            sleep(0.5)
            seriell_in(my_queue1, event)
        else:
            file1 = open(data['Dateipfad'], 'rb')
            print(data)
            s = (file1.read())
            #print(s)
            lae = file1.tell()
            file1.seek(0)
            print ('Die Datei hat ', lae , 'bytes')
            data2['Dateilaenge'] = lae
            #while data['Start'] == True:                          
            a = 0
            b = 0
            c = 0
            addr = [1]
            laenge = [1]
            while b < lae:
                data1 = file1.read(1)
                print(a, b, data1)
                if data1 == b'$':
                        data1 = file1.read(1)
                        print(a, b, data1)
                        b = b+1
                        if data1 == b'$':
                                data1 = file1.read(1)
                                print(a, b, data1) 
                                b = b+1
                                if data == b'$':
                                        data1 = file1.read(1)
                                        print(a, b, data1)
                                        b = b+1                            
                                        if data1 == b'$':
                                                data1 = file1.read(1)
                                                print(a, b, data1)
                                                b = b+1
                                                if data1 == b'$':
                                                        a = a+1
                                                        print(a, b, data1)                                                    
                                                        addr.append (b-4)                                  
                                                        laenge.append (addr[a] - addr[a-1])
                                                        print(addr[1])
                                    
                                        
                b = b+1
            a_ges = a    
            print ( 'Anzahl Datensätze: ' , str(a), 'Länge(byte) gesamt:  ', str(b))
            data2['Anzahl Datensaetze'] = a
            data2['Laenge(byte) gesamt'] = b
            file1.close()
            data['Start'] = False
            '''    
            a = 2
            while a <= a_ges:
                print('data' + ' ' + str(a) + ' ' + str(addr[a-1]) + ' ' + str(laenge[a]))
                file1.seek(addr[a])
                dataset = file1.read(laenge[a])
                data2['dataset'] = dataset  
                print(dataset, file1.tell())
                with serial.Serial('com1', 9600, timeout=2) as ser:
                    ser.write(dataset)
                    my_queue1.put(data2)
                    sleep(1)
                a = a+1
             '''   
            
            
                    
                
        


            
def generate_data(my_queue, event):
    while not event.is_set():
        data['Uhrzeit'] = dt.datetime.now().strftime('%d.%m.%Y\n%H:%M:%S')
        my_queue.put(data)
        #print(data['Dateiname'])
        #print(data['Startzeit'])
        #print(data['Start'])
        sleep(1.01)
        
class Application(tk.Frame):
    def __init__(self, my_queue, my_queue1, thread_kill_event, master=None):
        super().__init__(master)
        self.my_queue = my_queue
        self.my_queue1 = my_queue1
        self.thread_kill_event = thread_kill_event
        self.pack()
        self.create_widgets()
        self.update_labels()
        
    def create_widgets(self):
        
        self.label_text = tk.Label(self, height = 2, width = 15, fg = 'red', bg = 'yellow', text = 'TestText')
        self.label_text.pack()

        self.label_text2 = tk.Label(self, height = 2, width = 15, fg = 'red', bg = 'yellow', text = 'TestText')
        self.label_text2.pack()

        self.time_var = tk.StringVar()
        self.label_uhrzeit = tk.Label(self, height = 5, width = 30, fg = 'red', textvariable = self.time_var)
        self.label_uhrzeit.pack()

        self.auswahl = tk.Entry(self, width = 80)
        self.auswahl.pack()
          
        self.quit = tk.Button(self, text='QUIT', fg='red',command=self.exit_cleanup)
        self.quit.pack(side='right')

        self.start = tk.Button(self, text='Start', fg='blue', command=self.start)
        self.start.pack(side='right')
        
        self.auswahlBtn = tk.Button(self, text='Datei auswählen', command=self.dateipfad)
        self.auswahlBtn.pack(side='right')
        
        
        
        self.entryVar = tk.StringVar()
        self.entryVar.set('Dateiname: ')
        self.entry =tk.Entry(self)
        self.entry['textvariable'] = self.entryVar
        self.entry.pack(side='bottom')
        self.entry.bind('<Return>', self.handler)

        self.StartzeitVar = tk.StringVar()
        self.StartzeitVar.set('Startzeit: ')
        self.Startzeit =tk.Entry(self)
        self.Startzeit['textvariable'] = self.StartzeitVar
        self.Startzeit.pack(side='bottom')
        self.Startzeit.bind('<Return>', self.handler_startzeit)
        
    def start(self):
        if data['Start'] == False:
            data['Start'] = True
        else:
            data['Start'] = False
            
            
    def dateipfad(self):
        home = os.path.expanduser("~")
        datei_pfad = fd.askopenfilename(initialdir=home, title="Datei-Auswahl")
        self.auswahl.insert(tk.END, datei_pfad)
        data['Dateipfad'] = datei_pfad

    def handler(self, event):
        data['Dateiname'] = self.entryVar.get()
        
    def handler_startzeit(self, event):
        data['Startzeit'] = self.Startzeit.get()
           
        
    #holt die Datem aus der queue und aktualisiert die labels:
    def update_labels(self):
        self.master.after(500, self.update_labels)
        if not self.my_queue.empty():
            data = self.my_queue.get()
            self.time_var.set(data['Uhrzeit'])
            if data['Start'] == True:
                self.start['text'] = 'Stop'
            else:
                self.start['text'] = 'Start'
            #self.label_text['text'] = (data['Dateiname'])
        if not self.my_queue1.empty():
            data2 = self.my_queue1.get()
            self.label_text2['text'] = (data2['Dateilaenge']) 
             
    def exit_cleanup(self):
        self.thread_kill_event.set()
        self.master.destroy()





if __name__ == '__main__':
    main()

Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jürgen L.: Den Code in Tkinter und Thread musst Du für das bisher gezeigte eigentlich gar nicht zeigen, denn das sollte in einer Funktion passieren die `s` übergeben bekommt, und die Liste mit den Anfangspositionen zurück gibt. Da sollte nichts anderes irgendeinen Einfluss haben.

Threads und globale Variablen *und* noch GUI dazu. Nee, ne. ``global`` und globale Variablen haben ja so schon nix in Programmen zu suchen, aber wenn Du dann noch Threads und GUI-Code dazu schmeisst, kannst Du Dir auch gleich in den Fuss schiessen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

@__blackjack__: Du magst ja Recht haben, daß ich mich hier ganz schön weit aus dem Fenster lehne... aber ohne was zu probieren wird gar nichts !
und: ES FUNKTIONIERT erstmal; (runtime errors inclusive, weil der zweite thread nicht richtig beendet wird vermutlich)
und: die globale hab ich auch nur widerwillig eingeführt, weil der zweite thread über die Variable data gemeckert hat; danach gings dann...

Den Datenaustausch zwische GUI und Prozess über data{} halte ich aber immer noch für gut ! (weil: ich verstehe ihn...)
das habe ich in anderen Programmierumgebungen auch schon erfolgreich gemacht. (z.B. SPS mit codesys; ok hier werden wohl manche Nasen gerümpft, aber meine Haustechnik läuft damit ganz gut)

wenn ich dann später mal was besseres kennengelernt habe, werde ich das gern anwenden!

step for step... kann man sich in eine Programmierung einarbeiten - und: auf mein Erstlingswerk in Python bin ich stolz ! Deshalb bleibt mein Fuß heil !

Also nunmehr zurück zum eigentlichen Problem:
ich werde nun noch eine abgespeckte Variante testen, da mir wirklich nichts mehr einfällt, warum die identische Funktion in der Konsole andere Ergebnisse bringt.
Falls jemand noch Lust hat, sich damit zu beschäftigen stelle ich auch gern eine Testdatei zur Verfügung.

PS: wie im ersten post geschildert: isch bin hier der Neuling, so!
Benutzeravatar
sparrow
User
Beiträge: 4537
Registriert: Freitag 17. April 2009, 10:28

Jürgen L. hat geschrieben: Freitag 4. Januar 2019, 19:36Den Datenaustausch zwische GUI und Prozess über data{} halte ich aber immer noch für gut ! (weil: ich verstehe ihn...)
Nimm mir das nicht krumm, aber: Wenn du das das verstanden hättest, dann würde es funktionieren.
Setz die Tipps von Black_Jack um, denn darin liegt das Problem.
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

Problem war - wie so oft - ein Tipp_copy_paste_ oder sonstwas Fehler: bei der dritten If- Abfrage steht data statt data1... wenn in der abgespeckten Version data nicht mehr benutzt wird, kommt eine Fehlermeldung !
an den Dingen, die verbessert werden müssen arbeite ich... wie gesagt step for step
und: aus dem Alter, wo ich was krumm nehme bin ich lange raus...das sorgt aber auch manchmal für etwas längere 'Schaltzeiten'
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jürgen L.: Es funktioniert eben nicht. Selbst wenn es scheinbar funktionieren würde, wüsstest Du trotzdem nicht das es tatsächlich funktioniert, denn das ist ja gerade eines der grossen Probleme bei nebenläufiger Programmierung: die kann Fehler enthalten und trotzdem ”funktionieren”. Solange bis der nicht-deterministische Ablauf dann mal so ist, dass es in den Fehler rein rennt. Um solche Probleme zu minimieren hat man als erstes mal keinen globalen Zustand der alles irgendwie mit allem anderen verbindet. Du hast schon objektorientierte Programmierung und Du verwendest Queues zur Kommunikation. Da gibt es also keinen Grund für globale Variablen mehr.

Noch verwirrender wird es wenn Du sowieso schon komplett globale Datenstrukturen dann noch mal über einen Queue austauschst, wo man als Leser natürlich erst einmal davon ausgeht das die *nicht* global sind, weil man ja gerade um globale Variablen zu vermeiden, über Queues kommuniziert.

Die generischen, durchnummerierten Namen machen das ganze dann noch schwerer zu verstehen. Mindestens einer wird gar nicht verwendet, und mindestens an einer Stelle wird der falsche sehr ähnliche Name verwendet, was zu einem Fehler in dem angeblich funktionierenden Code führt.

Die `start()`-Methode wird nicht verwendet. Kann sie gar nicht, weil dieses Attribut durch eine Schaltfläche überschrieben wird, die auch `start` heisst.

Keine der beiden ``global``-Deklarationen macht Sinn, denn beide haben keine Auswirkungen auf den Programmablauf.

Der rekursive Aufruf von `seriell_in()` ist falsch. Bei mir würde dieser Thread spätestens nach 25 Minuten ohne zu starten deshalb mit einer Ausnahme abbrechen.

Der Präfix `my_` ist sinnfrei.

Zeichenkettenliterale sind nicht dazu da um Code auszukommentieren. Für Python selbst sind sie an bestimmten Stellen Docstrings. Für einige Werkzeuge sind sie an fast allen Stellen Docstrings.

Die Adressen und Längen sollten nicht in zwei ”parallelen” Listen gespeichert werden, die gehören ja offensichtlich zusammen. Also zum Beispiel als Tupel in einer Liste. Für die bessere Lesbarkeit vielleicht auch als `namedtupel` oder als eigener Datentyp.

Ich würde die wahrscheinlich mit Hilfe des `re`-Moduls ermitteln, denn die Match-Objekte haben ja netterweise die Start- und Endposition aus denen man die Länge trivial berechnen kann.

Für `generate_data()` braucht man keinen Thread, da reicht eine Methode und `after()`.

Widgets ordnen sich nicht selbst an. Das ``self.pack`` in `Application.__init__()` gehört da nicht hin.

Man macht keine Vergleiche mit literalen Wahrheitswerten. Da kommt ja wieder ein Wahrheitswert heraus, entweder der gleiche den man sowieso schon hatte, dann hätte man den auch gleich nehmen können, oder das Gegenteil, das bekommt man mit ``not``.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Jürgen L.
User
Beiträge: 8
Registriert: Freitag 4. Januar 2019, 15:28

@__blackjack__
Super ! Danke für die Zeit, die Du Dir genommen hast !
Sowas hilft wirklich weiter!
Ich werd versuchen, das umzusetzen und - wenns erlaubt ist - hier nochmal reinzustellen !
Das ganze ist übrigens zunächst für böse Hobbyzwecke...
stellt Euch eine Modellbahnanlage vor, bei der die Stellwerke über einen seriellen Bus kommunizieren...mit irgendwas muß man Fehler suchen und Steuertelegramme simulieren können...
Sowas gibts zwar fertig für viel Geld, aber das ist ja langweilig...
und: ich muß mir ne Bildschirmarbeitsbrille kaufen...
Antworten