I’ve been breaking my teeth on how to best save an array with key/value pairs and retrieve/update them. I am using rosv7.11 and tried many combinations but somehow i can’t seem to retrieve the data and access individual key/value pairs.
The datafile is saved as dataUsage and contains the following {month=8;total=631}
:local currentDate [/system clock get date];
:local currentMonth [:tonum [:pick $currentDate 5 7]];
:local dataFile "dataUsage.txt";
:if ([/file find name=$dataFile] = "") do={
# datausage.txt file does not exist so create with base values
/file add name=$dataFile contents="{month=$currentMonth;total=0}";
} else {
:local fileContent [/file get $dataFile contents];
:log info [:typeof $fileContent]; # returns string
:local fileData [:toarray $fileContent];
:log info [:typeof $fileData]; # returns array
:local fileMonth [:tonum ($fileData->"month")];
:log info ($fileData->"month"); # returns blank
:log info ($fileData->"total"); # returns blank
:if ($fileMonth=$currentMonth) do={
:log info "Same month";
# ... processing to be added
} else {
:log info "Different month $fileMonth/$currentMonth "; # $fileMonth is blank
:set ($fileData->"month") $currentMonth;
:set ($fileData->"total") 0;
}
/file remove $dataFile;
/file add name=$dataFile contents="{month=$($fileData->"month");total=$($fileData->"total")}";
}
Somehow I guess that either my initial saved array/string is not being correctly converted back to an array after reading from file or it is viewed as a single value but I can’t find where my mistake is.
Any insight would be much appreciated or if there is a better way to save and restore a few key/value pairs so that they persist at reboot that would be great.
That’s true, need quotes. But I think it the serializing an array to disk is the issue… I’m not sure this logic works:
:global before {field1="mystr";field2=2}
/file add name=diskarray contents=$before
:global after [:toarray [/file get diskarray contents]]
Also using this does not work either: “/file add name=diskarray contents=[:tostr $before]”
Both using the following tests:
# tests...
{
:put "File contains: $[/file get diskarray contents ]"
:put "Array length $[:len $before] should be 2..."
:put "After writing and reading to disk..."
:put "...it's length is $[:len $after] (typeof: $[:typeof $after]) containing:"
:put $after
:put "or \t$[:tostr $after]\tafter :tostr"
:put "with field1 being: $($after->"field1")"
:put "with index 0 being: $($after->0)"
/file remove diskarray
}
File contains: field1=mystr;field2=2
Array length 2 should be 2…
After writing and reading to disk…
…it’s length is 1 (typeof: array) containing:
field1=mystr;field2=2
or field1=mystr;field2=2 after :tostr
with field1 being:
with index 0 being: field1=mystr;field2=2
The month would be a number (8 for august) but that isn’t so much the problem.
The tests are exactly what I am experiencing as well …
If the serializing of the array to disk is not working with this logic, then how can/should this be done ?
:global test {month=“Aug”;test=0}
:put “:global test [:toarray ""]\r\n$[$exportarray $test]”
:global test [:toarray “”]
:set ($test->“month”) “Aug”
:set ($test->“test”) 0 EDIT 1-2-3-4: Fixed typos and added array declaration on file (:global test [:toarray “”]), remove duplicated [:toarray “”]., removed useless \r\n at the end of the cycle
One tip here, is there are really two kinds of arrays, “indexed lists” ($arr->0) and “key-value maps” ($arr->“key”) - even though both are :typeof == array. The key-value map ones you cannot get back from a string (without @rextended’s parsing code above)… but the list kind you can.
May not work here, but worth mentioning since if you can structure what you read/write to the more basic list array type, that does generally* work:
Hi,
I noticed that when I convert an array to a file each item in the array is separated by a “;”. So I wrote a script to find all the semicolons and then get all in between to create a new operational array.
I hope this helps you.
# Find a file in the Files List and turn it to operational Array
# Variables
:global ItemsArray;
:local DataFromFile;
:local Deviders;
:local SecondDevider;
# Find if the file exists
:local count 0;
:local L [/file print as-value];
:foreach f in=$L do={
:if (($f->"name")="DataFile.txt") do={
:set count ($count + 1);
}
}
# If the file exists then update it. If it doesn't exist then create it.
#:if ($count=0) do={ /file add name=DataFile.txt contents="";}
:if ($count=1) do={
# Find all the ; that devide all the items in the file
:set DataFromFile (";".[/file get DataFile.txt contents].";");
:set Deviders;
:for i from=0 to=([:len $DataFromFile] -1) do={
:local Char [:pick $DataFromFile $i ];
:if ($Char=";") do={
:set Deviders ($Deviders, $i);
}
}
# Make a new array from the items found in the file
:local z 1; # Used to calculate the SecondDevider
:set ItemsArray;
:foreach FirstDevider in=$Deviders do={
:set SecondDevider ($Deviders->$z);
:local Item [:pick $DataFromFile ($FirstDevider+1) $SecondDevider];
:set ItemsArray ($ItemsArray, $Item);
:set z ($z+1);
}
}
:put $ItemsArray;