Objekte als Datei speichern

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
bichlepa
Posts: 159
Joined: 15 Aug 2014, 06:44
GitHub: bichlepa
Contact:

Objekte als Datei speichern

09 Mar 2015, 16:23

Ich möchte für AutoHotFlow Objekte, die verschiedene Keys und Values haben, entweder als Datei oder als Eintrag in einer .ini Datei speichern. Das wird in AutoHotFlow für das Speichern von Listen als globale Variablen benötigt. Die Keys können entweder Nummern (wie in einem Array) oder alphanumerische Bezeichnungen sein.

Ich habe mir überlegt, alle Inhalte in einen speziell formatierten String zu speichern, den ich dann als ein Eintrag in eine .ini Datei schreiben kann. Beim Laden müsste ich diesen String parsen und das Objekt basteln. Damit wäre aber ein fehlerträchtiger und eventuell nicht sehr performanter Entwicklungsaufwand nötig. Daher frage ich, ob es auch einfacher geht.
Scripting is too complicated? Try AutoHotFlow, the graphical automation tool! Written in AutoHotkey.
User avatar
nnnik
Posts: 4317
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Objekte als Datei speichern

09 Mar 2015, 17:59

Also von der Performance musst du dir keine Gedanken machen.
Ich verstehe auch nicht wieso du 2 verschiedene Parser (ini und objekt) verwenden willst.

Code: Select all

D:=[{a:1,b:2,c:3},{a:2,b:3,c:1},{a:3,b:1,c:2}]
ObjToFile(D,"Test.dat")
F:=ObjFromFile("Test.dat")
Msgbox % F[1,"c"] . ", " . F[2,"b"] . ", " . F[3,"a"]

ObjToFile(Obj,Filename)
{
	Length:=ObjToBinary(Obj)
	VarSetCapacity(Bin,Length,0)
	ObjToBinary(Obj,&Bin)
	
	File:=FileOpen(Filename,"w")
	File.RawWrite(Bin,Length)
	File.Close()

	Return Length
}

ObjFromFile(Filename)
{
	
	File:=FileOpen(Filename,"r")
	File.RawRead(Bin,File.Length)
	File.Close()

	Return ObjFromBinary(&Bin)
}

ObjToBinary(Obj,Ptr=0)
{
	Len:=4
	Nr:=0
	Arr:=[]
	For Key, Value in Obj
	{
		Nr++
		Len+=StrPut(Key,"UTF-16")*2
		If (Value|0=="")
		{
			If IsObject(Value)
			{
				TypeNr:=3
				Len+=StrPut(GetClassName(Value),"UTF-16")*2
				Len+=ObjToBinary(Value)
			}
			Else
			{
				TypeNr:=0
				Len+=StrPut(Value,"UTF-16")*2
			}
		}
		Else
		{
			TypeNr:=1+!(InStr(Value,"."))
			Len+=8
		}
		Arr.Insert({Key:Key,Value:Value,TypeNr:TypeNr})
	}
	If !Ptr
		Return Len
	Ptr1:=Ptr+4
	Ptr2:=Ptr+Ceil(Nr/4)+4
	NumPut(Nr,(Ptr+0),"UInt")
	B:=C:=0
	For Index,KeyValue in Arr
	{
		B:=(B<<2)|KeyValue.TypeNr
		C++
		If (C=4)
		{
			NumPut(B,(Ptr1+0),"UChar")
			C:=B:=0
			Ptr+=1
		}
		Ptr2+=StrPut(KeyValue.Key,Ptr2,"UTF-16")*2
		If !KeyValue.TypeNr
			Ptr2+=StrPut(KeyValue.Value,Ptr2,"UTF-16")*2
		Else If (KeyValue.TypeNr<3)
		{
			NumPut(KeyValue.Value,(Ptr2+0),(KeyValue.TypeNr-1)?"Double":"Int64")
			Ptr2+=8
		}
		Else
		{
			Ptr2+=StrPut(GetClassName(KeyValue.Value),Ptr2,"UTF-16")*2
			Ptr2+=ObjToBinary(KeyValue.Value,Ptr2)
		}
	}
	Return Len
}

ObjFromBinary(Ptr,Obj="")
{
	If !Ptr
		Return
	If !IsObject(Obj)
		Obj:={}
	Ptr1:=Ptr
	Nr:=NumGet(Ptr1+0,"UInt")
	Ptr2:=(Ptr1+=4)+Ceil(Nr/16)
	C:=0
	Loop % Nr
	{
		C--
		If (C<0)
		{
			B:=NumGet(Ptr1+0,"UChar")
			Ptr+=1
			C:=4
		}
		TypeNr:=(B&0xC0)>>6
		B<<=2
		Key:=StrGet(Ptr2+0,"UTF-16")
		Ptr2+=StrPut(Key,"UTF-16")*2
		If (TypeNr=3)
		{
			ValueClass:=StrGet(Ptr2+0,"UTF-16")
			Ptr2+=StrPut(ValueClass,"UTF-16")*2
			If (ValueClass)
				Obj[Key]:=New %ValueClass%()
			Else
				Obj[Key]:={}
			Ptr2+=ObjFromBinary(Ptr2,Obj[Key])
		}
		Else If (TypeNr=1)
		{
			Obj[Key]:=NumGet(Ptr2+0,"Double")
			Ptr2+=8
		}
		Else If (TypeNr=2)
		{
			Obj[Key]:=NumGet(Ptr2+0,"Int64")
			Ptr2+=8
		}
		Else
		{
			Obj[Key]:=StrGet(Ptr2+0,"UTF-16")
			Ptr2+=StrPut(Obj[Key],"UTF-16")*2
		}
	}
	Return Obj
}

GetClassName(C)
{
	While (IsObject(C:=C.base)&&!C.HasKey("__Class"))
		Continue
	Return C.__Class
}
Recommends AHK Studio
User avatar
bichlepa
Posts: 159
Joined: 15 Aug 2014, 06:44
GitHub: bichlepa
Contact:

Re: Objekte als Datei speichern

10 Mar 2015, 03:05

Danke! Das ist ein vielversprechender Skript! Genau das, was ich gesucht habe! :D
Ich habe den mal ausprobiert. Es funktioniert aber nicht ganz. :( Bei eindimensionalen Arrays funktioniert es, aber bei mehrdimensionalen Arrays kommt es durcheinander.
Beispiel:

Code: Select all


D:=[{a:1,b:2,c:3},{a:2,b:3,c:1},{a:3,b:1,c:2}]
Msgbox % D[1]["c"] . ", " . D[2,"b"] . ", " . D[3,"a"] ;Ausgabe: 3, 3, 3
ObjToFile(D,"Test.dat")
F:=ObjFromFile("Test.dat")
Msgbox % F[1]["c"] . ", " . F[2,"b"] . ", " . F[3,"a"] ;Ausgabe: , ,

D:=["a","b", ["c","d"], "e"]
Msgbox % D[1] . ", " . D[2] . ", " . D[3][1] . ", " . D[3][2] . ", " . D[4] ;Ausgabe: a, b, c, d, e
ObjToFile(D,"Test.dat")
F:=ObjFromFile("Test.dat")
Msgbox % F[1] . ", " . F[2] . ", " . F[3][1] . ", " . F[3][2] . ", " . F[4] ;Ausgabe: a, b, c, d㐀, 

ObjToFile(Obj,Filename)
{
    Length:=ObjToBinary(Obj)
    VarSetCapacity(Bin,Length,0)
    ObjToBinary(Obj,&Bin)
    
    File:=FileOpen(Filename,"w")
    File.RawWrite(Bin,Length)
    File.Close()

    Return Length
}

ObjFromFile(Filename)
{
    
    File:=FileOpen(Filename,"r")
    File.RawRead(Bin,File.Length)
    File.Close()

    Return ObjFromBinary(&Bin)
}

ObjToBinary(Obj,Ptr=0)
{
    Len:=4
    Nr:=0
    Arr:=[]
    For Key, Value in Obj
    {
        Nr++
        Len+=StrPut(Key,"UTF-16")*2
        If (Value|0=="")
        {
            If IsObject(Value)
            {
                TypeNr:=3
                Len+=StrPut(GetClassName(Value),"UTF-16")*2
                Len+=ObjToBinary(Value)
            }
            Else
            {
                TypeNr:=0
                Len+=StrPut(Value,"UTF-16")*2
            }
        }
        Else
        {
            TypeNr:=1+!(InStr(Value,"."))
            Len+=8
        }
        Arr.Insert({Key:Key,Value:Value,TypeNr:TypeNr})
    }
    If !Ptr
        Return Len
    Ptr1:=Ptr+4
    Ptr2:=Ptr+Ceil(Nr/4)+4
    NumPut(Nr,(Ptr+0),"UInt")
    B:=C:=0
    For Index,KeyValue in Arr
    {
        B:=(B<<2)|KeyValue.TypeNr
        C++
        If (C=4)
        {
            NumPut(B,(Ptr1+0),"UChar")
            C:=B:=0
            Ptr+=1
        }
        Ptr2+=StrPut(KeyValue.Key,Ptr2,"UTF-16")*2
        If !KeyValue.TypeNr
            Ptr2+=StrPut(KeyValue.Value,Ptr2,"UTF-16")*2
        Else If (KeyValue.TypeNr<3)
        {
            NumPut(KeyValue.Value,(Ptr2+0),(KeyValue.TypeNr-1)?"Double":"Int64")
            Ptr2+=8
        }
        Else
        {
            Ptr2+=StrPut(GetClassName(KeyValue.Value),Ptr2,"UTF-16")*2
            Ptr2+=ObjToBinary(KeyValue.Value,Ptr2)
        }
    }
    Return Len
}

ObjFromBinary(Ptr,Obj="")
{
    If !Ptr
        Return
    If !IsObject(Obj)
        Obj:={}
    Ptr1:=Ptr
    Nr:=NumGet(Ptr1+0,"UInt")
    Ptr2:=(Ptr1+=4)+Ceil(Nr/16)
    C:=0
    Loop % Nr
    {
        C--
        If (C<0)
        {
            B:=NumGet(Ptr1+0,"UChar")
            Ptr+=1
            C:=4
        }
        TypeNr:=(B&0xC0)>>6
        B<<=2
        Key:=StrGet(Ptr2+0,"UTF-16")
        Ptr2+=StrPut(Key,"UTF-16")*2
        If (TypeNr=3)
        {
            ValueClass:=StrGet(Ptr2+0,"UTF-16")
            Ptr2+=StrPut(ValueClass,"UTF-16")*2
            If (ValueClass)
                Obj[Key]:=New %ValueClass%()
            Else
                Obj[Key]:={}
            Ptr2+=ObjFromBinary(Ptr2,Obj[Key])
        }
        Else If (TypeNr=1)
        {
            Obj[Key]:=NumGet(Ptr2+0,"Double")
            Ptr2+=8
        }
        Else If (TypeNr=2)
        {
            Obj[Key]:=NumGet(Ptr2+0,"Int64")
            Ptr2+=8
        }
        Else
        {
            Obj[Key]:=StrGet(Ptr2+0,"UTF-16")
            Ptr2+=StrPut(Obj[Key],"UTF-16")*2
        }
    }
    Return Obj
}

GetClassName(C)
{
    While (IsObject(C:=C.base)&&!C.HasKey("__Class"))
        Continue
    Return C.__Class
}
Ich habe es mit der Aktuellen AHK Version v1.1.20.00 probiert
nnnik wrote:Ich verstehe auch nicht wieso du 2 verschiedene Parser (ini und objekt) verwenden willst.
Vielleicht habe ich mich etwas missverständlich ausgedrückt. Meine Idee war, beim Speichern des Objekts das Objekt zu einem String zu machen und als ein Eintrag in eine .ini zu schreiben und beim Laden andersherum. So könnte ich mehrere Objekte in einer .ini Datei schreiben. Die Alternative zu ini ist, für jedes Objekt jeweils eine Datei zu verwenden.
Scripting is too complicated? Try AutoHotFlow, the graphical automation tool! Written in AutoHotkey.
User avatar
nnnik
Posts: 4317
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Objekte als Datei speichern

10 Mar 2015, 03:59

Oder vielleicht ein Array aus Objekten zu speichern?
Hmm.. Ich könnte schwören, dass es gestern noch funktioniert hat.
Recommends AHK Studio
User avatar
bichlepa
Posts: 159
Joined: 15 Aug 2014, 06:44
GitHub: bichlepa
Contact:

Re: Objekte als Datei speichern

10 Mar 2015, 04:08

Ich habe gerade beim Googeln nach "ObjToStr ahk" den Skript von LearningOne gefunden: http://www.autohotkey.com/board/topic/6 ... tructures/
Ich experimentiere gerade damit herum. Es scheint zu funktionieren und bietet zudem den Vorteil, dass die entstandenen Dateien sehr gut "human-readable" sind. Ich sage dann bescheid, ob es funktioniert. Es gibt aber noch einige Probleme im eigenen Code zu beseitigen.
Scripting is too complicated? Try AutoHotFlow, the graphical automation tool! Written in AutoHotkey.
User avatar
bichlepa
Posts: 159
Joined: 15 Aug 2014, 06:44
GitHub: bichlepa
Contact:

Re: Objekte als Datei speichern

10 Mar 2015, 10:51

Ich habe es mit dem Skript von LearningOne geschafft. :D
Ich habe den Skript auch so umgestaltet, dass jede globale Variable in AutoHotFlow in eine separate Datei geschrieben wird.

Trotzdem vielen Dank, nnnik, für deine Hilfe!
Scripting is too complicated? Try AutoHotFlow, the graphical automation tool! Written in AutoHotkey.

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 20 guests