A function returning file contents?

The key is that I want a function -- not a procedure.
Screenshot 2022-08-04 at 20-50-17 MIT App Inventor

Does it get any more simple than read, then return contents ?

Are you suggesting I call the function multiple times depending on the size of the file? There is no way of knowing when the global filedata has been updated.

How do you get the result from the "File1.GotText" event back to the "to readDataFile" function? You can see from the disabled block that I tried polling global readComplete and found it never changes. I understand why that is, but am looking for a solution to have a working function.

Just pass global filedata to where you want it to go in the File1.GotText event.

Are you talking about a component? I can't see that working for me. I need to do some processing on the data before it gets sent to a component (a canvas in this case). I thought about sending it to a hidden component, but still have the problem of knowing when it has been updated without a polling loop and that stops the event loop unfortunately.

Maybe you could add an extra function, is_file_ready(filename) to your app, to check a central dictionary (filename:contents) for previously read file content, and if necessary, initiate a read / update cycle? (Add the file:contents to the dictionary when they arrive.) Return true if available, false if too early.

This does not fix your determination to make an event-oriented architecture into a command and control architecture.

P.S. For an event-oriented architecture like AI2, the solution to this kind of problem is to envision the app as a factory floor with multiple workers, connected by conveyor belts (lists) delivering data to the worker stations.

A sample queue-driven app:
https://drive.google.com/open?id=1LxN548MWCCNZoQIrUye8EzvU8SEAHAp_

3 Likes

Do you really see reading a file as something that is event driven? This forces the whole file to be read even if only a small part of the data is important to you. I understand event driven thought processes. I worked with the tcl/tk stuff 30 years ago. To me it looks like reading a file has been forced into an event driven context. Maybe to add two numbers one should supply the two numbers to some block and wait for an event to give you the result.

The FAQ I linked in a prior post has fine essays by the designers of AI2 on the AI2 event model.

AI2 is meant to run on cell phones, with limited battery life and operating systems that demand their fair share of processor time. This is not a hardwired Arduino system, where you have access to all the power and processor cycles.

As I pointed out on a device that has limited memory perhaps one doesn't want to slurp in the whole file either.

Are you looking to use a file as a pipe, Unix-style?

I haven't seen it done yet in AI2.

It sounds like the kind of thing one of our enthusiastic extension writers would like to tackle.

P.S. If you check the Activity Starter component doc, there are facilities to start other apps with startup data, and to be started with startup data by another app.

Maybe this could be useful to you?

SQLite ?

A pipe was not my intention. My app has multiple files (the number of which isn't known before runtime) specified by the user. The information required from each file depends on other user inputs (mathematical formulas, let's say) and the contents read from previous files up until that point.

I don't know if it implemented pipes, but I ran across an extension the other day that did lots of other /bin/sh type of things. Sorry, but I don't recall the name of the extension.

Seems like one must always travel through Berlin or Tokyo on their way from Dallas to Fort Worth.

AI2 has in its File component a directory reading facility (I have not used it yet.)

If you have control over the incoming files' nomenclature, a datetimestamp file name prefix might be used to indicate which files are new, and the app could poll the directory for new files, under control of a Clock Timer (Sensors Drawer.)

You could always not save to file, but use the tinydb to store your user generated data, this is persistent on the app, and available without an event block to return the content.

I have used the listDirectory method. It is fairly simple but seemed to return all the Shared files on the device without regard to the directory that is specified if Shared scope is used. Legacy scope worked as expected. I didn't try the other scopes as my data is coming from /Download (external to the app).

The order things appear in the text string supplied by the user is important and changes what happens in the big loop. The only thing I can see that can work is to process the list and pre-fetch all the datafiles. This means I have to have enough available memory to hold every byte of every file even though I will eventually be discarding much of it. The ability to read a line or a fixed buffer length could eliminate this penalty.

The files are generated outside the app. I am already using tinydb to handle sharing between pages and to save the state of the app for later invocations. Is tinydb memory-based or "disk"-based? I didn't see many details in the docs.

Data for tinydb is saved to an XML file, buried in the private user area of the app.

Thanks for the info. Processing one huge XML file (padded with tags) multiple times doesn't sound very good for the battery life (used by someone above to justify event-driven system) as compared to having the ability to read the original files line by line or buffer by buffer. I do think MIT/Google didn't think this through very well. Treat file handling like the basic operation it is (my comment on addition above applies). Use the event handling loop to deal with user interactions like the methodology was originally designed to do.

As much as I hate Java, that's probably the way to resolve this. Reading a file just sounded so basic that I thought there should be a way to do it in a function.

By the way, the wait for event block I suggested at the beginning is still event-driven. It simply allows the "when file1.GotText" block to remain within the function's scope. When it is encountered the system can process the event loop like it normally does. Upon triggering instead of jumping to just after the separate "when" block, execution would return to just after the wait block inside the function. It would require the context of the function to be saved at the time of the "wait" and restored before continuing with the function execution.