write
Write files to the device filesystem.
- If the parent directory does not exist, it will be created.
- If the file already exists, it will be overwritten.
Two APIs are provided:
- write: returns a
Promisefor simple and quick file writing. - createWritable: returns a
SendSessionfor advanced use cases, allowing manual stream control and live progress tracking.
write
interface AdbSyncWriteOptions {
path: string;
type?: LinuxFileType;
permission?: number;
mtime?: number;
compression?: Compression.Format;
dryRun?: boolean;
}
declare class AdbSync {
write(
options: AdbSyncWriteOptions & {
readable: ReadableStream<MaybeConsumable<Uint8Array>>;
},
): Promise<Omit<SendSession, "writable">>;
}
Options
path: Path to the file on the device filesystem. Unlikecporadb pushcommands, it can't point to an existing directory, it must be the full path to the file to be created.readable: File content. It uses the Consumable pattern.type: File type, defaults toLinuxFileType.File. Can't beLinuxFileType.Directory.permission: File permission, defaults to0o644mtime: File modification time, defaults to current time (in seconds since Unix epoch).compression: The compression format to use for the file stream. Only available if device supportssendrecv_v2feature.dryRun: Iftrue, the file will not be written to the device filesystem. This was added for debugging and benchmarking purposes.
Compression
The compression option specifies the compression format to use when transferring the file:
- If
compressionisundefined, the best format supported by both the device and the current runtime is selected automatically. - If
Compression.Format.Noneis specified, compression is disabled. - Otherwise the explicitly specified format is used. If the format is not supported by either the device or runtime, an error is thrown.
See Compression for more details.
Example
import { encodeUtf8 } from "@yume-chan/adb";
const readable = new ReadableStream({
start(controller) {
controller.enqueue(encodeUtf8("Hello, world!"));
controller.close();
},
});
await sync.write({
path: "/sdcard/Download/hello.txt",
readable,
});
echo "Hello, world!" > hello.txt
adb push hello.txt /sdcard/Download/hello.txt
createWritable
For advanced use cases, createWritable returns a SendSession that allows manual control over the stream and progress tracking.
interface SendSession {
/**
* The writable stream to write the file content into.
*/
readonly writable: WritableStream<MaybeConsumable<Uint8Array>>;
/**
* Gets the number of bytes written into `writable`.
*/
readonly bytesWritten: number;
/**
* Gets the compression format used (might be `None`).
*/
readonly compression?: Compression.Format | undefined;
/**
* Gets the size of the compressed data sent to the device.
*/
readonly bytesCompressed: number;
}
declare class AdbSync {
createWritable(options: AdbSyncWriteOptions): Promise<SendSession>;
}
bytesWritten and bytesCompressed are live getters. You can poll them while writing to the writable stream to calculate real-time compression ratios or show progress in a UI.
Compression
See compression section above for details.
Example
- JavaScript
- TypeScript
const session = await sync.createWritable({
path: "/sdcard/large-file.bin",
});
const progressInterval = setInterval(() => {
const ratio = session.bytesCompressed / session.bytesWritten;
console.log(`Progress: ${session.bytesWritten} bytes, Ratio: ${ratio.toFixed(2)}`);
}, 1000);
try {
await readable.pipeTo(session.writable);
} finally {
clearInterval(progressInterval);
}
import type { AdbSync } from "@yume-chan/adb";
import { MaybeConsumable } from "@yume-chan/stream-extra";
declare const sync: AdbSync.Service;
declare const readable: ReadableStream<Uint8Array>;
const session = await sync.createWritable({
path: "/sdcard/large-file.bin",
});
const progressInterval = setInterval(() => {
const ratio = session.bytesCompressed / session.bytesWritten;
console.log(`Progress: ${session.bytesWritten} bytes, Ratio: ${ratio.toFixed(2)}`);
}, 1000);
try {
await readable.pipeTo(session.writable);
} finally {
clearInterval(progressInterval);
}
Internal API
Note: This is an internal API that is usually not needed directly. Most users should use the public API (adb.sync.write) instead.
The write method uses AdbSync.Send.send() internally, which operates on a SocketPool:
import type { SocketPool } from "@yume-chan/adb";
import { AdbSync, Compression } from "@yume-chan/adb";
declare const pool: SocketPool;
declare const path: string;
declare const readable: ReadableStream<Uint8Array>;
const session = await AdbSync.Send.send({
pool,
path,
readable,
version: 2, // or 1 for legacy protocol
compression: Compression.Format.Brotli, // optional
dryRun: false, // optional
});
Protocol versions
Version 1 (legacy):
- Uses
SENDrequest - No compression support
- Compatible with all Android versions
Version 2:
- Uses
SND2request - Supports compression (Brotli, LZ4, Zstd)
- Requires
sendrecv_v2feature (Android 10+) - Supports
dryRunmode for benchmarking
How it works
- Acquires a socket from the pool
- Sends a
SENDorSND2request with path and mode - Streams file data in chunks (default 64KB packets)
- Sends
DONEwith mtime when complete - Waits for
OKAYresponse - Automatically releases the socket back to the pool
The socket is automatically released after completion or error. If an error occurs during transmission, the socket is discarded to prevent connection corruption.