expo-file-system
Version:
Provides access to the local file system on the device.
213 lines (188 loc) • 7.13 kB
text/typescript
import ExpoFileSystem from './ExpoFileSystem';
import type { DownloadOptions, PathInfo } from './ExpoFileSystem.types';
import { PathUtilities } from './pathUtilities';
import { FileSystemReadableStreamSource, FileSystemWritableSink } from './streams';
export class Paths extends PathUtilities {
/**
* A property containing the cache directory – a place to store files that can be deleted by the system when the device runs low on storage.
*/
static get cache() {
return new Directory(ExpoFileSystem.cacheDirectory);
}
/**
* A property containing the bundle directory – the directory where assets bundled with the application are stored.
*/
static get bundle() {
return new Directory(ExpoFileSystem.bundleDirectory);
}
/**
* A property containing the document directory – a place to store files that are safe from being deleted by the system.
*/
static get document() {
return new Directory(ExpoFileSystem.documentDirectory);
}
static get appleSharedContainers() {
const containers: Record<string, string> = ExpoFileSystem.appleSharedContainers ?? {};
const result: Record<string, Directory> = {};
for (const appGroupId in containers) {
if (containers[appGroupId]) {
result[appGroupId] = new Directory(containers[appGroupId]);
}
}
return result;
}
/**
* A property that represents the total space on device's internal storage, represented in bytes.
*/
static get totalDiskSpace() {
return ExpoFileSystem.totalDiskSpace;
}
/**
* A property that represents the available space on device's internal storage, represented in bytes.
*/
static get availableDiskSpace() {
return ExpoFileSystem.availableDiskSpace;
}
/**
* Returns an object that indicates if the specified path represents a directory.
*/
static info(...uris: string[]): PathInfo {
return ExpoFileSystem.info(uris.join('/'));
}
}
/**
* Represents a file on the filesystem.
*
* A `File` instance can be created for any path, and does not need to exist on the filesystem during creation.
*
* The constructor accepts an array of strings that are joined to create the file URI. The first argument can also be a `Directory` instance (like `Paths.cache`) or a `File` instance (which creates a new reference to the same file).
* @example
* ```ts
* const file = new File(File.cache, "subdirName", "file.txt");
* ```
*/
export class File extends ExpoFileSystem.FileSystemFile implements Blob {
/**
* Creates an instance of a file. It can be created for any path, and does not need to exist on the filesystem during creation.
*
* The constructor accepts an array of strings that are joined to create the file URI. The first argument can also be a `Directory` instance (like `Paths.cache`) or a `File` instance (which creates a new reference to the same file).
* @param uris An array of: `file:///` string URIs, `File` instances, and `Directory` instances representing an arbitrary location on the file system.
* @example
* ```ts
* const file = new File(File.cache, "subdirName", "file.txt");
* ```
*/
constructor(...uris: (string | File | Directory)[]) {
super(Paths.join(...uris));
this.validatePath();
}
/*
* Directory containing the file.
*/
get parentDirectory() {
return new Directory(Paths.dirname(this.uri));
}
/**
* File extension.
* @example '.png'
*/
get extension() {
return Paths.extname(this.uri);
}
/**
* File name. Includes the extension.
*/
get name() {
return Paths.basename(this.uri);
}
readableStream() {
return new ReadableStream(new FileSystemReadableStreamSource(super.open()));
}
writableStream() {
return new WritableStream<Uint8Array>(new FileSystemWritableSink(super.open()));
}
async arrayBuffer(): Promise<ArrayBuffer> {
const bytes = await this.bytes();
return bytes.buffer as ArrayBuffer;
}
stream(): ReadableStream<Uint8Array<ArrayBuffer>> {
return this.readableStream();
}
slice(start?: number, end?: number, contentType?: string): Blob {
return new Blob([this.bytesSync().slice(start, end)], { type: contentType });
}
}
// Cannot use `static` keyword in class declaration because of a runtime error.
File.downloadFileAsync = async function downloadFileAsync(
url: string,
to: File | Directory,
options?: DownloadOptions
) {
const outputURI = await ExpoFileSystem.downloadFileAsync(url, to, options);
return new File(outputURI);
};
File.pickFileAsync = async function (initialUri?: string, mimeType?: string) {
const file = (await ExpoFileSystem.pickFileAsync(initialUri, mimeType)).uri;
return new File(file);
};
/**
* Represents a directory on the filesystem.
*
* A `Directory` instance can be created for any path, and does not need to exist on the filesystem during creation.
*
* The constructor accepts an array of strings that are joined to create the directory URI. The first argument can also be a `Directory` instance (like `Paths.cache`).
* @example
* ```ts
* const directory = new Directory(File.cache, "subdirName");
* ```
*/
export class Directory extends ExpoFileSystem.FileSystemDirectory {
/**
* Creates an instance of a directory. It can be created for any path, and does not need to exist on the filesystem during creation.
*
* The constructor accepts an array of strings that are joined to create the directory URI. The first argument can also be a `Directory` instance (like `Paths.cache`).
* @param uris An array of: `file:///` string URIs, `File` instances, and `Directory` instances representing an arbitrary location on the file system.
* @example
* ```ts
* const directory = new Directory(File.cache, "subdirName");
* ```
*/
constructor(...uris: (string | File | Directory)[]) {
super(Paths.join(...uris));
this.validatePath();
}
/*
* Directory containing the file.
*/
get parentDirectory() {
return new Directory(Paths.join(this.uri, '..'));
}
/**
* Lists the contents of a directory.
* Calling this method if the parent directory does not exist will throw an error.
* @returns An array of `Directory` and `File` instances.
*/
override list(): (Directory | File)[] {
// We need to wrap it in the JS File/Directory classes, and returning SharedObjects in lists is not supported yet on Android.
return super
.listAsRecords()
.map(({ isDirectory, uri }) => (isDirectory ? new Directory(uri) : new File(uri)));
}
/**
* Directory name.
*/
get name() {
return Paths.basename(this.uri);
}
createFile(name: string, mimeType: string | null): File {
// Wrapping with the JS child class for additional, JS-only methods.
return new File(super.createFile(name, mimeType).uri);
}
createDirectory(name: string): Directory {
return new Directory(super.createDirectory(name).uri);
}
}
Directory.pickDirectoryAsync = async function (initialUri?: string) {
const directory = (await ExpoFileSystem.pickDirectoryAsync(initialUri)).uri;
return new Directory(directory);
};