File System
Object-style File and Directory classes, the same shape as the new expo-file-system API. Reads and writes are plain Python file I/O, so they are fast and work the same everywhere. Downloads use URLSession on iOS and HttpURLConnection on Android. Every method also has its Expo camelCase name.
- pyxpo-file-system
- v0.1.0a1
- Native: Swift + Kotlin
- Like expo-file-system
Install
Install the package into the same environment as pyxpo.
Add file-system to modules in your app config, then import it in your code.
[tool.pyxpo]
modules = ["file-system"]from pyxpo_file_system import File, Directory, PathsThis module has native code. After you add it, run pyxpo run or pyxpo build again so it is compiled into the app. Hot reload alone is not enough.
Platforms
Quick start
from pyxpo_file_system import File, Paths
note = File(Paths.document, "note.txt")
note.write("Hello from Python")
print(note.text_sync()) # Hello from Python
print(note.size) # 17Permissions
pyxpo adds these to Info.plist and AndroidManifest.xml for you when the module is listed.
| iOS | None. |
|---|---|
| Android | INTERNET, for downloads. |
API reference
Paths
Paths.document→ DirectoryKept until the app is deleted. Backed up on iOS.
Paths.cache→ DirectoryThe system may clear it when space runs low.
Paths.available_disk_space / Paths.total_disk_space→ intBytes.
Paths.join(*parts) / dirname / basename(path, ext=None) / extname→ strPath string helpers.
File
File(Paths.document, "a", "b.txt"), a file:// URI or an absolute path. Creating the object does not touch the disk.
uri / name / path / extension / parent_directoryWhere the file is.
exists / size / md5 / modification_time / creation_time / typeLive values read from the disk.
text_sync() / bytes_sync() / base64_sync()→ str | bytesReads the whole file.
await text() / await bytes() / await base64()→ str | bytesAsync versions.
write(content, options=None, *, encoding="utf8", append=None)Writes str or bytes. encoding="base64" decodes a base64 string first. The folder must exist.
create(options=None, *, intermediates=None, overwrite=None)Creates an empty file. intermediates=True creates missing folders.
copy(dest) / move(dest) / rename(new_name) / delete()dest is a File or a Directory.
info(options=None, *, md5=None)→ dict{exists, uri, size, modificationTime, creationTime, md5?}. Times are in milliseconds.
open()→ FileHandleRandom access: offset, size, read_bytes(n), write_bytes(data), close().
Downloads
await File.download_file_async(url, destination, options=None)→ FileDownloads to a File or a Directory. A Directory keeps the server's file name. Raises on a non-2xx status. Options: {"headers": {...}, "idempotent": True} where idempotent replaces an existing file.
Directory
uri / exists / sizesize is the total of all files inside.
create(options=None, *, intermediates=None, overwrite=None, idempotent=None)idempotent=True does nothing when the folder exists.
list()→ list[File | Directory]Direct children.
list_as_records()→ list[dict]Children as plain records.
create_file(name, mime_type=None) / create_directory(name)Creates a child.
copy / move / rename / delete / info()Same as File.
Legacy API
The classic expo-file-system functions, for code ported from Expo SDK 53 and older.
from pyxpo_file_system import legacy as FileSystemdocumentDirectory, get_info_async, read_as_string_async, write_as_string_async, delete_async, move_async, copy_async, make_directory_async, read_directory_async, download_async, get_free_disk_storage_async. camelCase aliases also work.
Examples
Save and load JSON
Keep app data in a folder inside Paths.document.
import json
from pyxpo_file_system import Directory, File, Paths
folder = Directory(Paths.document, "notes")
folder.create(idempotent=True)
f = File(folder, "today.json")
f.write(json.dumps({"title": "Groceries", "done": False}))
data = json.loads(f.text_sync())
names = [item.name for item in folder.list()]Download a file
Download into the cache folder and keep the server's file name.
from pyxpo_file_system import Directory, File, Paths
async def fetch_report():
dest = Directory(Paths.cache, "downloads")
dest.create(intermediates=True, idempotent=True)
out = await File.download_file_async(
"https://example.com/report.pdf", dest,
{"idempotent": True, "headers": {"Accept": "application/pdf"}},
)
return out.uriRead part of a large file
Use a FileHandle to read bytes from any position without loading the whole file.
from pyxpo_file_system import File, Paths
h = File(Paths.document, "video.mp4").open()
h.offset = 1024
header = h.read_bytes(64)
h.close()Good to know
- File and Directory objects are cheap. They only point at a path until you call a method.
- Writing into a folder that does not exist raises an error. Create it first, or use create(intermediates=True).
- Files from the image picker are in the cache folder. Copy them to Paths.document to keep them.