Skip to first unread message

Harry Mangurian

unread,
Feb 25, 2017, 9:27:35 PM2/25/17
to MIT App Inventor Forum
I stored a text file using the blocks shown below.
Later in my app I read the file using (again) just the file name.
I put the file contents into a textbox and the text is correct, so everything works.

  1. Just so I can learn, where on my phone or emulator is the file stored. I searched for it by file name and could not locate it.
  2. Where would it be stored if I had used "/testtextfile.txt" instead ?
  3. Is there a tutorial or lesson where I can read up on file addresses in general when using AI2 ?
Thanks,



Taifun

unread,
Feb 26, 2017, 10:40:16 AM2/26/17
to MIT App Inventor Forum
see the documentation http://ai2.appinventor.mit.edu/reference/components/storage.html#File

SaveFile(text text, text fileName)
Saves text to a file. If the filename begins with a slash (/) the file is written to the sdcard (for example, writing to /myFile.txt will write the file to /sdcard/myFile.txt). If the filename does not start with a slash, it will be written in the program's private data directory where it will not be accessible to other programs on the phone. There is a special exception for the AI Companion where these files are written to /sdcard/AppInventor/data to facilitate debugging. Note that this block will overwrite a file if it already exists. If you want to add content to a file use the append block.

Taifun

Trying to push the limits of App Inventor! Snippets, Tutorials and Extensions from Pura Vida Apps by Taifun. 

Harry Mangurian

unread,
Feb 26, 2017, 11:14:19 AM2/26/17
to MIT App Inventor Forum
excellent.   Thanks

Min Sullivan

unread,
Mar 1, 2017, 3:08:44 PM3/1/17
to MIT App Inventor Forum
Hello again!

Your response is very helpful for me, too.  I have some questions about files, please:
  1. The app I am working on makes lists out of the text in the file.  Should I convert to and from csv format when writing to and reading from the file?
  2. Is there a limit to the amount of text data that can be stored in a file?
  3. The app I am working on uses a file it creates on the device it's being used on.  I want the user of the app to be able to get that file and send (email, etc.) it to another device.  In that device, I want the user to be able to tell the [same] app on that device to replace the text in the file it created and uses with the text in the file that was sent from the other device.  Is there a file picker that the user could use to give the app the filepath to the file sent from the other device?

Abraham Getzler

unread,
Mar 1, 2017, 3:31:33 PM3/1/17
to MIT App Inventor Forum
  1. The app I am working on makes lists out of the text in the file.  Should I convert to and from csv format when writing to and reading from the file?

You definitely need a text representation of your list(s).
CSV format is good for simple lists and tables, one per file.
More complex data structures should be wrapped in JSON 
for clarity and flexibility.
Web search for JSON Introduction for examples.

Abg
 

Min Sullivan

unread,
Mar 1, 2017, 3:36:42 PM3/1/17
to MIT App Inventor Forum
Will do!

Can you have a list of lists in CSV?  From what I'm seeing in my searches, it looks like no.

Abraham Getzler

unread,
Mar 1, 2017, 3:42:20 PM3/1/17
to MIT App Inventor Forum
Can you have a list of lists in CSV?  From what I'm seeing in my searches, it looks like no

A csv table is a list of lists.

Look for the project "states" in the Gallery for an example loading a table from a file.

ABG
 

Min Sullivan

unread,
Mar 1, 2017, 3:43:38 PM3/1/17
to MIT App Inventor Forum
Thanks so much!

Taifun

unread,
Mar 1, 2017, 3:45:04 PM3/1/17
to MIT App Inventor Forum
use the list to csv table block to convert a 2 dimensional list of lists into a csv table, for more dimensions use JSON as ABG suggested

Taifun

Min Sullivan

unread,
Mar 1, 2017, 3:46:56 PM3/1/17
to MIT App Inventor Forum
Can I do a list of JSON values?

Abraham Getzler

unread,
Mar 1, 2017, 4:14:29 PM3/1/17
to MIT App Inventor Forum
See this doc for my latest JSON project ...

After you understand it,
if you want more advanced work,

Warning - JSON schemas are in JSON, leading you to swirl around in a whirlpool of metadata if you stray too far from the shore.
Best to start out simple.

ABG

Min Sullivan

unread,
Mar 1, 2017, 5:46:20 PM3/1/17
to MIT App Inventor Forum
I slapped together an app to test my knowledge of how to get the values from a JSON file.  Turns out JSON code is the same as JavaScript when it comes to arrays and objects, so I understand JSON files.

In your example you're only reading from a JSON file.  Is there a simple way to update a JSON file, after it's JsonTextDecoded?  My JSON file is a list of objects, the objects of keys.  Is there a simple way to add another object of keys to the list?  A simple way to change the value of a key in one of the objects in the list?  I hope I'm not swirling down a whirlpool of metadata too far from sure shore...

Thanks for all your help!

Abraham Getzler

unread,
Mar 1, 2017, 6:56:02 PM3/1/17
to MIT App Inventor Forum
Updating a list inside another list in AI2 is tricky.
it's all pointers at that level.

There's a new flag in SCreen1 that turns on JSON conversion of lists when they are assigned into text.

I would use a JOIN with an empty string to force that conversion,
and keep simple lists of JSON strings to do just simple list replace operations at the top level,
before forcing a new JSON conversion.

If you stay with lists of lists, use the copy list block or build
entirely new structures with updated results to avoid pointing to dead data.

I do some of that in my JSON editor project.

ABG

Min Sullivan

unread,
Mar 1, 2017, 7:45:30 PM3/1/17
to MIT App Inventor Forum
I could make a list of keys and a list of values.  Then I could use the find item in list block to find the index at which the key I want is.  I could get or replace the value at that index in the values list.  Whenever I made a change, I could copy the list that includes the other lists and lists of lists to the file.

One problem, though.  How will App Inventor know how to recreate those lists of lists of lists from the file's text?  I can't tell App Inventor to separate at commas.  Does the JSON conversion of lists that you mentioned take care of that?  I couldn't quite wrap my mind around your explanation.

Min Sullivan

unread,
Mar 1, 2017, 7:47:00 PM3/1/17
to MIT App Inventor Forum
For that matter, how could I store a list of a lists in a file and then re-create those lists from the file?

Taifun

unread,
Mar 1, 2017, 8:24:12 PM3/1/17
to MIT App Inventor Forum
convert the list of lists into csv format and store the csv table in the file
btw. probably easier would be to store the list of lists in TinyDB without need to convert it...

Abraham Getzler

unread,
Mar 1, 2017, 8:48:09 PM3/1/17
to MIT App Inventor Forum
TinyDB is very update friendly if you can figure out how to build up tags that will identify table, row, and column all in one string.  See my Tinydb_export_import app in the Gallery.
ABG

Abraham Getzler

unread,
Mar 1, 2017, 9:02:31 PM3/1/17
to MIT App Inventor Forum

Abraham Getzler

unread,
Mar 1, 2017, 9:21:28 PM3/1/17
to MIT App Inventor Forum
Regarding creating JSOn codes of your own, attached are blocks for how to do it recursively.
I coded them for the ability to limit the parse depth, to defend against lists that point to themselves.
(See my Ouroboros example in the Gallery )

Unfortunately, it only works for 3 of 4 sample JSON examples .
AI2 does not guarantee recursion will always work.

ABG

blocks.png
JSON_encoder.aia

Min Sullivan

unread,
Mar 2, 2017, 3:00:28 PM3/2/17
to MIT App Inventor Forum
Thanks!  If I have lists inside of lists inside of lists, could I still convert to CSV format and store the table in the file?

I know it sounds crazy, but:
My app is a talking app.
There are levels in the app, that can be switched between using a list view.
In each level the sprites say texts when clicked.  The texts for each sprite are different in each level.
In each level each sprite also has a different x and y coordinate, etc.

I want to store a list, one list item for each sprite.
Each list items will be a list of the levels.
Each item in the list of levels will be a list of text, x, y, etc.

The user is allowed to add and delete levels and edit the details of each sprite in each level.

TinyDB has a character limit for each tag.  I would make a tag for each sprite in each level, but the user can add and delete levels, so having a list makes more sense.  That would be a list 3 lists deep (list inside a list inside a list):
sprites list
     levels list
          text, x, y, etc. list

That's why I need to know if I can convert a list 3 lists deep (list inside a list inside a list) to CSV format and store the table in the file.  Any advice?  Maybe I'm making this too complicated...
I would make a file for each sprite, but when the user switches levels I would have to get as many files as I have sprites, and that's a lot.

Min Sullivan

unread,
Mar 2, 2017, 3:01:50 PM3/2/17
to MIT App Inventor Forum
Thanks!  I'll look at your projects.  Ad I'll be using that webpage you pointed me to for a future project!

Min Sullivan

unread,
Mar 2, 2017, 4:33:55 PM3/2/17
to MIT App Inventor Forum
I tried to make a program that would allow the user to create, edit, and get results from a file.  When the file is created, I use the list to csv table block.  In the socket are lists inside of lists inside of lists, just like I'd be using for my Talker app.  Unfortunately, when I try to make the csv tables back into lists of lists of lists, it gives me a runtime error.  I have included screenshots of my test app.  How do you make lists of lists of lists into text for the file, and then re-create the lists of lists of lists from the file's text?
Screen shot 2017-03-02 at 4.28.48 PM.png
Screen shot 2017-03-02 at 4.29.16 PM.png
Screen shot 2017-03-02 at 4.29.26 PM.png
Screen shot 2017-03-02 at 4.30.18 PM.png

Min Sullivan

unread,
Mar 2, 2017, 4:34:54 PM3/2/17
to MIT App Inventor Forum
 Look at the last two screenshots first...

Min Sullivan

unread,
Mar 2, 2017, 4:40:03 PM3/2/17
to MIT App Inventor Forum
Attached is a screenshot of keys.  I'm trying to emulate keys and values, like in JSON.  The make a list [true, "text"]s is in the order of the keys list:
KEY  ---  value
Visible --- true
Text --- "text"
Screen shot 2017-03-02 at 4.36.33 PM.png

Min Sullivan

unread,
Mar 2, 2017, 5:01:13 PM3/2/17
to MIT App Inventor Forum
Hang on.  I had the select list item [list, index] backwards...  See attached screen capture.  Don't know what to do about list from csv table [text], though, when I'm trying to re-make the lists from the text.

I just made a successful version of the testing program with lists only 2 levels deep...
Screen shot 2017-03-02 at 4.58.38 PM.png
Screen shot 2017-03-02 at 4.58.49 PM.png

Abraham Getzler

unread,
Mar 2, 2017, 5:25:03 PM3/2/17
to MIT App Inventor Forum
I think you have a data modelling problem.

You have to flatten your data so it does not have more than 2 dimensions.

Lists inside lists of lists is 3 dimensions; that's beyond the csv limit of just 2 dimensions.

You need to switch to a table with more key columns and a compound key.
Have you seen the relational data model yet?

Your character table might look like:
character ID (PK)
character picture
character level (PK)
character's text
character's sprite component (at run time only)
character's X (for load/save)
character's Y (")

That's 7 columns (at least).

This can be done with Fusion Tables
(pk = Primary Key,  if each character can simultaneously be on multiple levels, otherwise just character ID is the key.)

See this doc for how to filter a list of lists (table) by column  to simulate SELECT with multiple WHERE clauses ...

ABG

Min Sullivan

unread,
Mar 2, 2017, 6:37:04 PM3/2/17
to MIT App Inventor Forum
I considered fusion tables earlier, but I want my app to work without Internet connection.  Wouldn't be good if someone relying on the app found themselves in a place without Internet and therefore couldn't communicate.  I'd use fusion tables otherwise...

Great article.  Do you have a website of your programming articles?

As for the Talking app data modeling problem, maybe I could squash that 3rd dimension by:
  1. Making a list for each level.
  2. Making a list inside the levels list with the particulars (visible, text, x, y, etc.) all in that list.  It would be like:
    Levels list item 1:
         Sprite 1 visible
         Sprite 1 text
         all the others for Sprite 1
         Sprite 2 visible
         Sprite 2 text
         all the others for Sprite 2
         and on and on for the other sprites
    Levels list item 2:
         follows the pattern of Levels list item 1
  3. Then I could make a function.  The function would multiply the number of the sprite who's details (visible, text, x, y, etc.) I need by the number of details each sprite has (a global variable), and add to that the item index of the detail I need (1 for visible, 2 for text, 3 for x, 4 for y, etc.).  The number the function ends with would be the id in the list (inside the levels list) of the detail I need.

I think that will work.  Thank you so much!!!  One more question: In App Inventor is there a limit to the number of items a list can contain?  If so, I'm sunk, since the lists inside the levels list will be quite lengthy I estimate.

Abraham Getzler

unread,
Mar 2, 2017, 6:55:27 PM3/2/17
to MIT App Inventor Forum
Try to think in terms of the logical data model first before you try to optimize it in a physical data model.

What are your objects and their attributes?

What depends on what?

How many sentences can you write of the form:

A ___ has one/many ___ ?


ABG


Taifun

unread,
Mar 2, 2017, 6:58:48 PM3/2/17
to mitappinv...@googlegroups.com
I considered fusion tables earlier, but I want my app to work without Internet connection
you could use the local SQlite database, see my SQlite extension here https://puravidaapps.com/sqlite.php

Taifun

Min Sullivan

unread,
Mar 2, 2017, 7:32:35 PM3/2/17
to MIT App Inventor Forum
That looks awesome! I can't really afford it right now, though.

Min Sullivan

unread,
Mar 2, 2017, 7:58:55 PM3/2/17
to MIT App Inventor Forum
There are many sprites.

A sprite has many levels.

A level has many values.

There are only level values for existing levels.

I'll do the objects and attributes in another post...

Min Sullivan

unread,
Mar 2, 2017, 8:01:47 PM3/2/17
to MIT App Inventor Forum
My objects are:
Visible (in use)
Text to say
Web link or file path for image
The web link or image path
Width of image (for displaying as sprite)
Height of image (for the same)
X coordinate of sprite
Y coordinate of sprite
Z value if sprite

Abraham Getzler

unread,
Mar 3, 2017, 11:32:23 AM3/3/17
to MIT App Inventor Forum
Thanks! If I have lists inside of lists inside of lists, could I still 

convert to CSV format and store the table in the file?
 

 After sleeping on this question, I remembered a trick I used in my TinyDB_export_import sample
to turn the entire contents of TinyDB, including tags and values that might
be simple values, lists, and tables (lists of lists) into a single piece of text
that could be written to a file, and imported and reconstructed later.

The core of the technique is to take the outer 2 branch levels of a 
three level tree and temporarily replace them with their csv table text,
reducing the depth needed for further csv text conversion.

There's a limit to how far this technique can be pushed, involving
AI2's (and yours) ability to unravel quotes of quotes of quotes.

ABG


Abraham Getzler

unread,
Mar 3, 2017, 11:37:46 AM3/3/17
to MIT App Inventor Forum
About JSON - JSON is the data equivalent of the multiple layers of cardboard, bubble wrap, 
plastic peanuts, inner boxes, plastic bags, twist ties, and IKEA assembly instruction sheets
that accompany a product you buy over the Internet.

 It's fine for storage and transport across programs, but it's awkward to live out of.

ABG

Min Sullivan

unread,
Mar 3, 2017, 2:29:57 PM3/3/17
to MIT App Inventor Forum
So if I use that technique I would create a sprite list.

Each item in the sprite list would be a levels list. Each item in the levels list would be a details (visible, text, x,y, etc.) list translated into a csv row.

Min Sullivan

unread,
Mar 3, 2017, 2:33:03 PM3/3/17
to MIT App Inventor Forum
To edit a details list I would translate a levels list item from csv to a list, edit the newly created list, and translate the lust back to csv.

Am I correct or do I misunderstand?

Abraham Getzler

unread,
Mar 3, 2017, 4:33:15 PM3/3/17
to MIT App Inventor Forum
So if I use that technique I would create a sprite list.

Each item in the sprite list would be a levels list.  Each item in the levels list would be a details (visible, text, x,y, etc.) list translated into a csv row


To edit a details list I would translate a levels list item from csv to a list, edit the newly created list, and translate the list back to csv.

Am I correct or do I misunderstand?


So your key hierarchy is: sprite, level, detailname ?
And you have a simple value to save or load for each combination (sprite,level,detail)?

The simplest and easiest way to do this is to build up a TinyDB tag from a 5-way text JOIN (spriteName, '/', levelNameorNumber, '/', detailName)
and store that detail value under that tag.

That would eliminate a boat load of complexity.

ABG

Min Sullivan

unread,
Mar 3, 2017, 4:53:37 PM3/3/17
to MIT App Inventor Forum
That would work awesome, but:
Levels can be created and deleted. Levels are navigated with a listview. I need the levels to be a list to work with the creating and deleting the user is allowed to do. At least, I think so.

Abraham Getzler

unread,
Mar 3, 2017, 4:57:04 PM3/3/17