Clarification: syntax for file name description

I just want to clarify the new way to write file names with Codea 3.x.

The file name used to be just a string such as
tt=readText(“Dropbox:file1”)

But since Codea 3.x introduced assets key stile, the code should be
tt= readText( asset.documents.Dropbox … “file1.txt”)
blanks are required before and after “…” in order to connect asset location description and file name with file type extension.

file name can be a variable
fileName=“file1.txt”
tt=readText(asset.documents.Dropbox … fileName)

However, when choosing the file directly from code editor, it can be written as
tt= readText( asset.documents.Dropbox._file1)
no blanks nor file type are required but an underscore.

Are there any other points to be noted in syntax for file name description?

@Makoto It depends if the file exists or not. Blanks aren’t required before the …
If the file exists, then you can just tap between the () and select it. If the file doesn’t exist or it has special characters in the name, then you might need “” or [] or … with the name. It also depends if you specify the extension name with the file name. Normally if the file exists, I just select it in between the (). If the file doesn’t exist yet, then I just try different things around the name until I don’t get a warning. I don’t know if there’s specific rules for what to do for each situation. It kind of varies because sometimes it works multiple ways.

    f=readText(asset.documents.Dropbox["bkA200505-1640.txt"])
    f=readText(asset.documents.Dropbox"bkA200505-1640.txt")
    f=readText(asset.documents.Dropbox.test3)
    f=readText(asset.documents.Dropbox..qwert)

    saveText(asset.documents.Dropbox.."qwert-123.txt")
    saveText(asset.documents.Dropbox.test3)
    saveText(asset.documents.Dropbox..qwert)
    
    f=readImage(asset.documents.Dropbox.test2_png)
    f=readImage(asset.documents.Dropbox..test22_png)
    
    saveImage(asset.documents.Dropbox.sky)
    saveImage(asset.documents.Dropbox..qwert)
        
    sprite(asset.documents.Dropbox.sky)
    sprite(asset.documents.Dropbox..sky45.png)

@Makoto an underscore shouldn’t be necessary unless the file begins with a character that can’t be used in Lua (like a space, number, or symbol)

You should be able to write

readText( asset.documents.file1 )

If a file called file1.txt exists in your documents folder

If the file doesn’t exist (say you want to create it, using saveText), you can specify the path as follows:

saveText( asset.documents .. "file1.txt", "Hello World" )

More notes on underscores:

Because you can’t use certain symbols in variable names in Lua (they can’t start with a number, they can’t contain a space, they can’t contain quotes, etc.) you will see them replaced with underscores when you select them via autocomplete or through the picker

For example, a file called "A Hero's Quest:Tavern Music" would be represented as asset.builtin.A_Hero_s_Quest.Tavern_Music (because Lua doesn’t let you put space ( ), or quote (') in variable names.

You could also access this file with the raw strings by doing:

asset.builtin["A Hero's Quest"]["Tavern Music"]

Is there a useful way to find out if the file exists in code?

@RonJeffries I think I mentioned something similar already. It used to be if you tried to read a file that didn’t exist, it returned nil and you could code for that. Now, if you try to read a file that doesn’t exist, the code exits with an error. I haven’t checked recently if that was corrected or not.

PS. Just tried it and the code exits with an error.

@RonJeffries there isn’t a good way to do it, but that’s a great question. I will add an exists property to the asset key system so you can check whether an asset exists in the file system

@dave1707 I’m getting nil when reading a text file that doesn’t exist

local blah = readText( asset.documents .. "MadeUpFile.txt" )
print(blah)

@Simeon I guess it just depends on the syntax. I didn’t have the “ “ around my file name. It didn’t give me an error in the editor, so I thought it was OK. It just gave an error message when I tried to run the code. I’ll just have to remember to put “ “ around the name.

@Simeon Here’s what I mean about the syntax. It’s like you need to try different things. Some times you need a single period, other times you need a double period , or double quotes or double brackets. I thought maybe if you didn’t get an editor error message, then it should work. So from what you said, everything should work OK. You just need to try different combinations until it does.

function setup()
    str1=readText(asset.documents.Dropbox.test3)        -- file exist, reads OK
    str2=readText(asset.documents.Dropbox.."test3")     -- file exists, returns nil
    str3=readText(asset.documents.Dropbox.."test31")    -- file doesn't exist, returns nil
    print("str1 ",str1)
    print("str2 ",str2)
    print("str3 ",str3)
end

@dave1707 when you use quotes " you must use the full filename, including the extension.

function setup()
    str1=readText(asset.documents.Dropbox.test3)        -- file exist, reads OK
    str2=readText(asset.documents.Dropbox.."test3.txt")     -- (assuming the file has a .txt extension)
    str3=readText(asset.documents.Dropbox.."test31")    -- file doesn't exist, returns nil
    print("str1 ",str1)
    print("str2 ",str2)
    print("str3 ",str3)
end

When you get the autocompleted identifiers for files the file extensions are not included — unless two or more files with the same name (but different extensions) live in the same folder. So if you had “test3.txt” and “test3.png” in your Dropbox you would get

asset.documents.Dropbox.test3_txt and
asset.documents.Dropbox.test3_png

Whereas if you only have “test3.txt” in the folder you’d get an autocomplete identifier like:

asset.documents.Dropbox.test3

If you want to use the actual file name you can do that with the bracket syntax:

asset.documents.Dropbox["test3.txt"]

@Simeon I thought I fully understood the asset syntax, but I guess I didn’t. Thanks for the added info.

@RonJeffries here’s a little app that lets you check if a file exists

-- File Exists
function setup()
    print("Checking asset.builtin.Effects")

    local folder = asset.builtin.Effects        
    
    parameter.text("FileName", "Ripple.shader", function ()        
        exists = doesExist(FileName, folder)        
    end)
    
    parameter.action("List Folder", function ()
        for _,v in pairs(folder.all) do
            print(v.name)
        end
    end)
    
    exists = doesExist(FileName, folder)
end

function doesExist(name, folder) 
    return folder[name] ~= nil
end


function draw()
    background(40, 40, 50)

    strokeWidth(5)

    fill(255)
    textMode(CENTER)
    if exists then
        text("File Exists", WIDTH/2, HEIGHT/2)
    else 
        text("File Does Not Exist", WIDTH/2, HEIGHT/2)
    end
end

Basically you check if folder[fileName] ~= nil. If you get an asset key, then the file exists. If you get nil, it doesn’t.

So if asset.documents["MySprite.png"] is nil, then it’s not there.

Side note: this is different to asset.documents .. "MySprite.png". The concatenation (..) operator will create an asset key for you by appending a given file name to a folder name, this allows you to specify asset keys for files which don’t exist (so you can create them)

thanks!

in the … examples simeon and dave show above, i’d have expected to have to say …“.text3”, not just …“text3”, etc.

@RonJeffries .. is the concatenation operator, and in this case it is used to construct a new path given an existing folder and a file/folder name

So it might make more sense to expect folder .. "/text3.txt". As you are appending onto a path, though in this API we omit the path separator (/) because where and how to place path separators when concatenating path elements should be handled by the system

I’ll be writing a more interesting file and asset example soon

my thought is that “asset.documents” … “test.txt” is “asset.documentstest.txt” not “asset.documents.test.txt” but I suppose it’s just an overload of “…” with smarts.

ok, so

saveImage(asset.documents.Dropbox.."unitpic.png", img)

saves, you guessed it, to On My iPad > Codea > Dropbox.assets

Is that related to Dropbox at all? How do I specify an arbitrary location in Files, and where is this documented, please?

@RonJeffries yeah asset.documents represents the path to the folder “Documents/”

asset.documents.Dropbox represents “Documents/Dropbox.assets/”

At the moment you cannot specify an arbitrary location in Files. But this is why I introduced asset keys, it implements the architecture I need to get there

iOS restricts access to files, so Codea cannot read or write any files on your system outside of its own Documents folder. The only way Codea can access another folder is if we present the system file picker and you explicitly select a folder or file. Codea will be granted access to only that folder or file and can store a bookmark to it

This is what I’m planning to introduce with asset keys — something like you type asset. and in the autocomplete bar there is a button for “External Folder”, and tapping that brings up the file picker UI, selecting the folder then creates a bookmark for Codea and allows you to reference the folder in your code

it’s weird. i’m sure you’ll get there. thanks!

I wish to have a sub-folder capability within Dropbox, taking advantage of the asset keys system.
I mean something like;
textRead(asset.documents.Dropbox.folder1[“test3.txt”])
Then I can save a set of data relating to one project in one folder together. It will make easier not only to manage numerous files for number of projects but also to implement auto linkage of required files in exporting a zipped project file to Xcode.
Currently, it seems Codea detects the files in the folder “Dropbox/???/Codea” only and classify them by their file types, e.g. text, image, sound, etc. However, it ignores subfolders under Codea folder.
Codea project editor deems “.folder1” following Dropbox as an asset and give me an error message “Asset ‘folder1’ does not exist”, even there is a subfolder “filder1” in the Codea folder.