@@ -12,6 +12,8 @@ File streams are ideal for handling large files where loading entire content int
1212- ** Event-Driven** : Use Nitro callbacks for real-time progress updates
1313- ** Cross-Platform** : Consistent API across iOS and Android
1414
15+ > ** Note:** The stream API is now binary-only. All encoding/decoding (e.g., UTF-8, Base64) must be handled in JavaScript. Native code only receives and returns ` ArrayBuffer ` .
16+
1517## Read Stream API
1618
1719### ` createReadStream(path: string, options?: ReadStreamOptions): Promise<ReadStreamHandle> `
@@ -29,12 +31,9 @@ Creates a read stream for efficiently reading large files in chunks.
2931``` typescript
3032interface ReadStreamOptions {
3133 bufferSize? : number ; // Buffer size in bytes (default: 4096)
32- encoding? : StreamEncoding ; // 'utf8' | 'ascii' | 'base64' | 'arraybuffer' (default: 'arraybuffer')
3334 start? : bigint ; // Start position in bytes (default: 0)
3435 end? : bigint ; // End position in bytes (default: file end)
3536}
36-
37- type StreamEncoding = ' utf8' | ' ascii' | ' base64' | ' arraybuffer' ;
3837```
3938
4039#### ReadStreamHandle
@@ -96,7 +95,6 @@ interface ReadStreamDataEvent {
9695 data: ArrayBuffer ; // Raw data chunk
9796 chunk: bigint ; // Chunk number (0-based)
9897 position: bigint ; // Current position in file
99- encoding: StreamEncoding ;
10098}
10199
102100interface ReadStreamProgressEvent {
@@ -122,39 +120,37 @@ interface ReadStreamErrorEvent {
122120### Read Stream Example
123121
124122``` typescript
125- import { Fs2 } from ' react-native-fs2-nitro' ;
123+ import { Fs2 , concatenateArrayBuffers , listenToReadStreamData , listenToReadStreamProgress , listenToReadStreamEnd , listenToReadStreamError } from ' react-native-fs2-nitro' ;
126124
127125async function readLargeFile() {
128126 try {
129127 // Create read stream
130128 const stream = await Fs2 .createReadStream (' /path/to/large-file.dat' , {
131- bufferSize: 8192 , // 8KB chunks
132- encoding: ' arraybuffer'
129+ bufferSize: 8192 // 8KB chunks
133130 });
134131
135132 let totalData = new ArrayBuffer (0 );
136133
137134 // Listen for data chunks
138- const unsubscribeData = Fs2 . listenToReadStreamData (
135+ const unsubscribeData = listenToReadStreamData (
139136 stream .streamId ,
140137 (event ) => {
141138 console .log (` Received chunk ${event .chunk }, ${event .data .byteLength } bytes ` );
142-
143139 // Accumulate data (for small files) or process chunk immediately
144140 totalData = concatenateArrayBuffers (totalData , event .data );
145141 }
146142 );
147143
148144 // Listen for progress updates
149- const unsubscribeProgress = Fs2 . listenToReadStreamProgress (
145+ const unsubscribeProgress = listenToReadStreamProgress (
150146 stream .streamId ,
151147 (event ) => {
152- console .log (` Progress: ${event .progress .toFixed (1 )}% (${event .bytesRead }/${event .totalBytes }) ` );
148+ console .log (` Progress: ${( event .progress * 100 ) .toFixed (1 )}% (${event .bytesRead }/${event .totalBytes }) ` );
153149 }
154150 );
155151
156152 // Listen for completion
157- const unsubscribeEnd = Fs2 . listenToReadStreamEnd (
153+ const unsubscribeEnd = listenToReadStreamEnd (
158154 stream .streamId ,
159155 (event ) => {
160156 console .log (' Stream finished successfully' );
@@ -165,7 +161,7 @@ async function readLargeFile() {
165161 );
166162
167163 // Listen for errors
168- const unsubscribeError = Fs2 . listenToReadStreamError (
164+ const unsubscribeError = listenToReadStreamError (
169165 stream .streamId ,
170166 (event ) => {
171167 console .error (' Stream error:' , event .error );
@@ -202,7 +198,6 @@ Creates a write stream for efficiently writing large files in chunks.
202198``` typescript
203199interface WriteStreamOptions {
204200 append? : boolean ; // Append to existing file (default: false)
205- encoding? : StreamEncoding ; // 'utf8' | 'ascii' | 'base64' | 'arraybuffer' (default: 'arraybuffer')
206201 bufferSize? : number ; // Internal buffer size (default: 4096)
207202 createDirectories? : boolean ; // Create parent directories if needed (default: true)
208203}
@@ -217,9 +212,6 @@ interface WriteStreamHandle {
217212 // Write data chunk to stream
218213 write(data : ArrayBuffer ): Promise <void >;
219214
220- // Write string data (when encoding is utf8 or base64)
221- writeString(data : string ): Promise <void >;
222-
223215 // Flush any buffered data
224216 flush(): Promise <void >;
225217
@@ -281,27 +273,26 @@ interface WriteStreamErrorEvent {
281273### Write Stream Example
282274
283275``` typescript
284- import { Fs2 } from ' react-native-fs2-nitro' ;
276+ import { Fs2 , listenToWriteStreamProgress , listenToWriteStreamFinish , listenToWriteStreamError } from ' react-native-fs2-nitro' ;
285277
286278async function writeLargeFile() {
287279 try {
288280 // Create write stream
289281 const stream = await Fs2 .createWriteStream (' /path/to/output-file.dat' , {
290282 append: false ,
291- encoding: ' binary' ,
292283 createDirectories: true
293284 });
294285
295286 // Listen for progress
296- const unsubscribeProgress = Fs2 . listenToWriteStreamProgress (
287+ const unsubscribeProgress = listenToWriteStreamProgress (
297288 stream .streamId ,
298289 (event ) => {
299290 console .log (` Written: ${event .bytesWritten } bytes ` );
300291 }
301292 );
302293
303294 // Listen for completion
304- const unsubscribeFinish = Fs2 . listenToWriteStreamFinish (
295+ const unsubscribeFinish = listenToWriteStreamFinish (
305296 stream .streamId ,
306297 (event ) => {
307298 console .log (' Write completed:' , event .bytesWritten , ' bytes' );
@@ -311,7 +302,7 @@ async function writeLargeFile() {
311302 );
312303
313304 // Listen for errors
314- const unsubscribeError = Fs2 . listenToWriteStreamError (
305+ const unsubscribeError = listenToWriteStreamError (
315306 stream .streamId ,
316307 (event ) => {
317308 console .error (' Write error:' , event .error );
@@ -341,110 +332,45 @@ async function writeLargeFile() {
341332
342333## Utility Functions
343334
344- ### Text Processing with Streams
335+ ### Text and Binary Processing with Streams
345336
346337``` typescript
347- // Read text file in chunks with specific encoding
348- async function readTextStream(filePath : string , encoding : ' utf8' = ' utf8' ) {
349- const stream = await Fs2 .createReadStream (filePath , { encoding });
350- let content = ' ' ;
351-
352- return new Promise <string >((resolve , reject ) => {
353- const unsubscribeData = Fs2 .listenToReadStreamData (stream .streamId , (event ) => {
354- // Convert ArrayBuffer to string based on encoding
355- const chunk = arrayBufferToString (event .data , encoding );
356- content += chunk ;
357- });
338+ import { readStream , writeStream } from ' react-native-fs2-nitro' ;
358339
359- const unsubscribeEnd = Fs2 . listenToReadStreamEnd ( stream . streamId , () => {
360- unsubscribeData ();
361- unsubscribeEnd ( );
362- resolve ( content );
363- });
340+ // Read a file as a string (text mode)
341+ async function readTextFile( filePath : string , encoding : ' utf8 ' = ' utf8 ' ) {
342+ const content = await readStream ( filePath , encoding );
343+ // content is a string
344+ }
364345
365- const unsubscribeError = Fs2 .listenToReadStreamError (stream .streamId , (event ) => {
366- unsubscribeData ();
367- unsubscribeEnd ();
368- unsubscribeError ();
369- reject (new Error (event .error ));
370- });
346+ // Read a file as binary (default)
347+ async function readBinaryFile(filePath : string ) {
348+ const buffer = await readStream (filePath ); // default is 'arraybuffer'
349+ // buffer is an ArrayBuffer
350+ }
371351
372- stream .start ();
373- });
352+ // Write a string to a file (text mode)
353+ async function writeTextFile(filePath : string , text : string , encoding : ' utf8' = ' utf8' ) {
354+ await writeStream (filePath , text , encoding );
374355}
375356
376- // Write text with streaming
377- async function writeTextStream(filePath : string , text : string , encoding : ' utf8' = ' utf8' ) {
378- const stream = await Fs2 .createWriteStream (filePath , { encoding });
379-
380- const data = stringToArrayBuffer (text , encoding );
381- await stream .write (data );
382- await stream .close ();
357+ // Write binary data to a file (default)
358+ async function writeBinaryFile(filePath : string , buffer : ArrayBuffer ) {
359+ await writeStream (filePath , buffer ); // default is 'arraybuffer'
383360}
384361```
385362
386363### File Copy with Progress
387364
388365``` typescript
389- async function copyFileWithProgress(
366+ import { copyFileWithProgress } from ' react-native-fs2-nitro' ;
367+
368+ async function copyFileWithProgressExample(
390369 sourcePath : string ,
391370 destPath : string ,
392371 onProgress ? : (progress : number ) => void
393372) {
394- const readStream = await Fs2 .createReadStream (sourcePath , { bufferSize: 16384 });
395- const writeStream = await Fs2 .createWriteStream (destPath , { bufferSize: 16384 });
396-
397- return new Promise <void >((resolve , reject ) => {
398- let unsubscribeData: (() => void ) | null = null ;
399- let unsubscribeProgress: (() => void ) | null = null ;
400- let unsubscribeEnd: (() => void ) | null = null ;
401- let unsubscribeError: (() => void ) | null = null ;
402-
403- const cleanup = () => {
404- unsubscribeData ?.();
405- unsubscribeProgress ?.();
406- unsubscribeEnd ?.();
407- unsubscribeError ?.();
408- };
409-
410- // Forward read data to write stream
411- unsubscribeData = Fs2 .listenToReadStreamData (readStream .streamId , async (event ) => {
412- try {
413- await writeStream .write (event .data );
414- } catch (error ) {
415- cleanup ();
416- reject (error );
417- }
418- });
419-
420- // Track progress
421- if (onProgress ) {
422- unsubscribeProgress = Fs2 .listenToReadStreamProgress (readStream .streamId , (event ) => {
423- onProgress (event .progress );
424- });
425- }
426-
427- // Handle completion
428- unsubscribeEnd = Fs2 .listenToReadStreamEnd (readStream .streamId , async () => {
429- try {
430- await writeStream .close ();
431- cleanup ();
432- resolve ();
433- } catch (error ) {
434- cleanup ();
435- reject (error );
436- }
437- });
438-
439- // Handle errors
440- unsubscribeError = Fs2 .listenToReadStreamError (readStream .streamId , (event ) => {
441- cleanup ();
442- reject (new Error (event .error ));
443- });
444-
445- // Start the copy
446- readStream .start ();
447- });
373+ await copyFileWithProgress (sourcePath , destPath , { bufferSize: 16384 , onProgress });
448374}
449375```
450376
@@ -461,19 +387,7 @@ async function copyFileWithProgress(
461387
4623884 . ** Threading** : Stream operations run on background threads, keeping the UI responsive
463389
464- 5 . ** Encoding** : Use 'arraybuffer' encoding for maximum performance when dealing with raw data
465-
466- ## Platform Differences
467-
468- ### iOS
469- - Uses ` NSInputStream ` and ` NSOutputStream ` for efficient native streaming
470- - Supports all encoding types natively
471- - File system permissions handled automatically
472-
473- ### Android
474- - Uses ` FileInputStream ` and ` FileOutputStream ` with buffer management
475- - UTF-8 and Base64 encoding handled efficiently
476- - Respects Android scoped storage requirements
390+ 5 . ** Encoding** : All encoding/decoding is handled in JavaScript. Native code only deals with ` ArrayBuffer ` .
477391
478392## Error Codes
479393
@@ -501,13 +415,15 @@ ReactNativeBlobUtil.fs.readStream(path, encoding, bufferSize)
501415 });
502416
503417// fs2-nitro style
504- const stream = await Fs2 .createReadStream (path , { encoding , bufferSize });
418+ const stream = await Fs2 .createReadStream (path , { bufferSize });
505419const unsubscribeData = Fs2 .listenToReadStreamData (stream .streamId , event => {
506420 /* handle event.data */
507421});
422+
508423const unsubscribeEnd = Fs2 .listenToReadStreamEnd (stream .streamId , () => {
509424 /* handle end */
510425});
426+
511427await stream .start ();
512428```
513429
0 commit comments