Stream methods provide low-level access to file transfers, allowing you to work with ReadableStream and WritableStream interfaces for more control over data flow.
When using stream methods, you must call finalizeStream after completing the transfer to release locks and close connections properly.
downloadReadable
Download a file from the server using a ReadableStream interface.
public async downloadReadable(fileName: string): Promise<ReadableStream<Uint8Array>>
Parameters
The path to the file on the FTP server to download.
Return type
stream
Promise<ReadableStream<Uint8Array>>
Returns a promise that resolves to a ReadableStream that you can read data from.
Example
const stream = await client.downloadReadable('/path/to/file.txt');
// Option 1: Use with a Response object
const response = new Response(stream);
const text = await response.text();
// Don't forget to finalize
await client.finalizeStream();
// Option 2: Read chunks manually
const stream = await client.downloadReadable('/path/to/largefile.bin');
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Process chunk
console.log(`Received ${value.byteLength} bytes`);
}
} finally {
reader.releaseLock();
await client.finalizeStream();
}
// Option 3: Using AsyncDisposable interface
{
using stream = await client.downloadReadable('/path/to/file.txt');
// Stream is automatically finalized when exiting the block
const data = await new Response(stream).arrayBuffer();
}
This method is ideal for handling large files or when you need to process data in chunks as it arrives.
uploadWritable
Upload a file to the server using a WritableStream interface.
public async uploadWritable(
fileName: string,
allocate?: number
): Promise<WritableStream<Uint8Array>>
Parameters
The path where the file should be saved on the FTP server.
The number of bytes to allocate for the file. Some FTP servers require this parameter to pre-allocate disk space.
Return type
stream
Promise<WritableStream<Uint8Array>>
Returns a promise that resolves to a WritableStream that you can write data to.
Example
const content = new TextEncoder().encode('Hello, World!');
const stream = await client.uploadWritable('/path/to/file.txt', content.byteLength);
const writer = stream.getWriter();
try {
await writer.write(content);
await writer.close();
} finally {
await client.finalizeStream();
}
// Upload a large file in chunks
const stream = await client.uploadWritable('/path/to/largefile.bin', totalSize);
const writer = stream.getWriter();
try {
for (const chunk of dataChunks) {
await writer.write(chunk);
}
await writer.close();
} finally {
await client.finalizeStream();
}
// Using AsyncDisposable interface
{
using stream = await client.uploadWritable('/path/to/file.txt');
const writer = stream.getWriter();
await writer.write(data);
await writer.close();
// Stream is automatically finalized when exiting the block
}
The allocate parameter sends an ALLO command to the FTP server. If the server doesn’t require allocation, it will typically respond with code 202 (command not implemented) which is handled gracefully.
finalizeStream
Unlock and close connections for streaming operations.
public async finalizeStream(): Promise<void>
Return type
Returns a promise that resolves when the stream is finalized and all resources are released.
Example
const stream = await client.downloadReadable('/path/to/file.txt');
const data = await new Response(stream).arrayBuffer();
// Always finalize the stream
await client.finalizeStream();
You must call this method after using downloadReadable or uploadWritable. Failing to do so will leave connections open and locks unreleased, preventing subsequent operations.
This method performs the following operations:
- Closes the data connection
- Closes the writable stream
- Waits for the server’s transfer complete status (code 226)
- Releases the internal lock
Alternative: AsyncDisposable
If your runtime supports AsyncDisposable (using declarations), you can avoid manually calling finalizeStream:
// Automatically finalized when exiting the block
{
using stream = await client.downloadReadable('/path/to/file.txt');
const data = await new Response(stream).text();
}
// Stream is automatically finalized here