On Android, many functions dealing with files and directories will return Storage Access Framework (SAF) or MediaStore URIs instead of conventional path specifications like they are used on desktop systems. The advantage of content URIs, i.e. SAF and MediaStore URIs, is that they can point to virtually all kinds of different locations, i.e. they are not limited to files and directories on the local device but could also specify files stored in clouds like Google Drive. This makes it very flexible to work with them because using URIs makes it very easy to load files from the cloud or store data in the cloud.
Nevertheless, a few things are to be kept in mind when working with those URIs: First of all, when creating a new file using a content URI it's not enough to simply call OpenFile() using a write IO mode like you can do with normal files. All files stored using content URIs must be created first before you can write to them. Thus, you must first call CreateFile() and pass the desired URI. This will then create an empty (zero byte) file for you. After that you can open the file for writing using OpenFile() just as you do with normal files.
Secondly, content URIs use a different format than normal file paths, e.g. the content URI of a picture in your phone's media gallery might look like this:
content://media/external_primary/images/media/1000039788 |
As you can see, there is no traditional file name and extension specification in that URI at all. Instead, the URI is in some sort of custom format that can only be interpreted by the respective Android components. It's also different from device to device and there can be lots of differences between Android versions. Thus, you mustn't make any assumptions about content URIs and you mustn't manually compose them by just concatenating path components. It's also not possible to parse content URIs using functions like FilePart() or PathPart() because of their opaque custom format. If you want to find out the filename specified by a content URI, you have to use GetFileAttributes() or FileAttributes() to do that.
Content URIs must only be composed using the right functions. For example, the functions FileRequest() or PathRequest() will return content URIs that you can work with. Let's suppose you want to save a file to a user-selected location, then you could do it like this:
p$ = PathRequest("Select path")
uri$ = CreateFile(p$, "test.txt") ; this is important, see above!
OpenFile(1, uri$, #MODE_WRITE)
WriteLine(1, "Hello World!")
CloseFile(1)
|
Of course, you could also use FileRequest() in save mode instead. In that case, FileRequest() will already create the file and you don't have to call CreateFile() at all:
uri$ = FileRequest("Select file", {Mode = #REQ_SAVEMODE})
OpenFile(1, uri$, #MODE_WRITE)
WriteLine(1, "Hello World!")
CloseFile(1)
|
If you want to open a file but you don't have its full content URI but just the content URI of its path, you can use FullPath() to create a content URI that contains the path and the filename, e.g. like this:
p$ = PathRequest("Select path")
uri$ = FullPath(p$, "test.txt")
OpenFile(1, uri$)
l$ = ReadLine(1)
CloseFile(1)
|
If you want to create a new file in one of MediaStore's default folders, you can do it like this:
uri$ = CreateFile(#MEDIA_IMAGES, "test.png", {MIMEType = "image/png"})
SaveBrush(1, uri$, {Format = #IMGFMT_PNG})
|
To load that file later, you could do this:
uri$ = FullPath(#MEDIA_IMAGES, "test.png") LoadBrush(1, uri$) |
Since FullPath() can only return content URIs to existing files or directories you cannot use it if you would like to construct a content URI for a non-existing file or directory. This is why you can't use MakeDirectory() to create a new directory using a content URI: It only accepts a single argument so it is impossible to be used with content URIs because we can't compose a content URI that points to a non-existing directory. Thus, you need to use CreateDirectory() to create a new directory using a content URI because that function takes two arguments, e.g. like this:
p$ = PathRequest("Select directory")
uri$ = CreateDirectory(p$, "Test")
|
The code above creates a directory named "Test" in the directory selected by the user.
Most of Hollywood's DOS library functions can be used with content URIs just fine. There are only the following exceptions: MoveFile() and SetFileAttributes() are unsupported for content URIs and both CopyFile() and DeleteFile() can only be used on single files, not on directories. When using DeleteFile() on a content URI directory, the directory must be empty or it will fail. Also, if the content URI is a MediaStore URI then it's not possible to create directories and it's also not possible to iterate over all files in a MediaStore directory. Both of these things are only possible with SAF URIs, i.e. the ones returned by functions like FileRequest() and PathRequest().
These were the most important things to be kept in mind when working with content URIs. As you can see, most of the things are identical to normal paths. There are only a few cases that need special attention.