| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: Local File Access | 
					
						
							| 
									
										
										
										
											2023-02-28 11:40:44 +00:00
										 |  |  | pagination_prev: demos/data/index | 
					
						
							|  |  |  | pagination_next: demos/cloud/index | 
					
						
							|  |  |  | sidebar_custom_props: | 
					
						
							|  |  |  |   summary: Reading and writing files using various platform APIs | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 11:21:37 +00:00
										 |  |  | import current from '/version.js'; | 
					
						
							|  |  |  | import CodeBlock from '@theme/CodeBlock'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | Reading from and writing to files requires native platform support. | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | SheetJS `readFile` and `writeFile` methods include support for some platforms. | 
					
						
							|  |  |  | Due to sandboxing and security settings, `readFile` does not work in the web | 
					
						
							|  |  |  | browser and `writeFile` is not guaranteed to work in all cases. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | This demo looks at various web APIs for reading and writing files. We'll explore | 
					
						
							|  |  |  | how to pass data between SheetJS functions and various APIs. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | :::note pass | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Some snippets are also available in the "Common Use Cases" section: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | - [Data Import](/docs/solutions/input) | 
					
						
							|  |  |  | - [Data Export](/docs/solutions/output) | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | Other demos cover APIs for local file access on special platforms: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - ["iOS and Android Apps"](/docs/demos/mobile/) covers mobile app frameworks | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  | - ["Desktop Apps"](/docs/demos/desktop/) covers desktop apps | 
					
						
							|  |  |  | - ["Command-Line Tools"](/docs/demos/cli) covers standalone command-line tools | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ## Binary Data
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | JavaScript engines represent binary data in a number of structures. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | The `type` option for SheetJS `read` function[^1] controls how the data should | 
					
						
							|  |  |  | be interpreted. This parameter distinguishes [binary strings](#binary-strings) | 
					
						
							|  |  |  | from [Base64 strings](#base64-strings). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `type` option for SheetJS `write` function[^2] controls the output storage. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### `Uint8Array` and `Buffer`
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | A `Uint8Array` is a Typed Array where each value is a 8-bit unsigned integer. | 
					
						
							|  |  |  | Server-side platforms including NodeJS typically use `Uint8Array`, or a subclass | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | such as `Buffer`[^3], to represent data from files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `read` method can read data from `Uint8Array` without any options: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const wb = XLSX.read(u8); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `write` method can generate workbooks stored in | 
					
						
							|  |  |  | `Uint8Array` structures with the option `type: "buffer"`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const u8 = XLSX.write(wb, {bookType: "xlsx", type: "buffer"}); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In NodeJS, the `write` method will generate a `Buffer` instance. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ### `ArrayBuffer`
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | An `ArrayBuffer` represents an array of bytes. The `Uint8Array` constructor can | 
					
						
							|  |  |  | synchronously create a view without copying the underlying data: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | /* create a Uint8Array "view" */ | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | const u8 = new Uint8Array(array_buffer); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `read` method can read data from `ArrayBuffer` without special | 
					
						
							|  |  |  | options, as it performs the aforementioned conversion. The SheetJS `write` | 
					
						
							|  |  |  | method can generate workbooks stored in `ArrayBuffer` structures with the | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | option `type: "array"` | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ### `Blob` and `File`
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | `Blob` is an opaque pointer to data. The data is not immediately accessible. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | `File` extends `Blob` with support for storing file names and other metadata. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The SheetJS `read` method does not handle `Blob` or `File`. The underlying data | 
					
						
							|  |  |  | must be pulled into an `ArrayBuffer` before parsing. There are two approaches: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A) Modern browsers support the `arrayBuffer` method. It returns a promise that | 
					
						
							|  |  |  | resolves to `ArrayBuffer`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | // usage: const wb = await blob_to_wb(blob); | 
					
						
							|  |  |  | async function blob_to_wb(blob) { | 
					
						
							|  |  |  |   const ab = await blob.arrayBuffer(); // pull data from Blob | 
					
						
							|  |  |  |   return XLSX.read(ab);                // parse ArrayBuffer | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | B) For broader browser support, the `FileReader` API can pull `ArrayBuffer` data | 
					
						
							|  |  |  | using the `readAsArrayBuffer` method: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | // usage: file_to_wb(file, function(wb) { /* wb is a workbook object */ }); | 
					
						
							|  |  |  | function file_to_wb(file, callback) { | 
					
						
							|  |  |  |   var reader = new FileReader(); | 
					
						
							|  |  |  |   reader.onload = function(e) { | 
					
						
							|  |  |  |     /* e.target.result is an ArrayBuffer */ | 
					
						
							|  |  |  |     callback(XLSX.read(e.target.result)); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   reader.readAsArrayBuffer(file); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>FileReaderSync in Web Workers</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | `FileReaderSync` is only available in Web Workers. It returns an `ArrayBuffer`: | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | // assuming main thread called worker.postMessage({ file: file_object }) | 
					
						
							|  |  |  | self.addEventListener('message', (e) => { | 
					
						
							|  |  |  |   /* get file object from message */ | 
					
						
							|  |  |  |   var file = e.data.file; | 
					
						
							|  |  |  |   /* Read file data */ | 
					
						
							|  |  |  |   const ab = new FileReaderSync().readAsArrayBuffer(file); | 
					
						
							|  |  |  |   /* Parse file */ | 
					
						
							|  |  |  |   const wb = XLSX.read(ab); | 
					
						
							|  |  |  |   /* DO SOMETHING WITH wb HERE */ | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 11:21:37 +00:00
										 |  |  | ["User-Submitted File" example](/docs/demos/bigdata/worker#user-submitted-file) | 
					
						
							|  |  |  | includes a live demo. | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The SheetJS `write` method can generate a `Uint8Array` which can be passed to | 
					
						
							|  |  |  | the `Blob` constructor: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | function wb_to_blob(wb, bookType) { | 
					
						
							|  |  |  |   /* write workbook to Uint8Array */ | 
					
						
							|  |  |  |   const u8 = XLSX.write(wb, { bookType: bookType || "xlsx", type: "buffer" }); | 
					
						
							|  |  |  |   /* create array of parts */ | 
					
						
							|  |  |  |   const parts = [ u8 ]; // `Blob` constructor expects this | 
					
						
							|  |  |  |   /* create Blob */ | 
					
						
							|  |  |  |   const blob = new Blob(parts, { type: "application/vnd.ms-excel" }); | 
					
						
							|  |  |  |   return blob; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ``` | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The `File` constructor accepts an additional `name` argument: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | function wb_to_file(wb, filename) { | 
					
						
							|  |  |  |   /* impute bookType from file extension */ | 
					
						
							|  |  |  |   const ext = filename.slice(filename.lastIndexOf(".") + 1); | 
					
						
							|  |  |  |   /* write workbook to Uint8Array */ | 
					
						
							|  |  |  |   const u8 = XLSX.write(wb, { bookType: ext, type: "buffer" }); | 
					
						
							|  |  |  |   /* create array of parts */ | 
					
						
							|  |  |  |   const parts = [ u8 ]; // `File` constructor expects this | 
					
						
							|  |  |  |   /* create File */ | 
					
						
							|  |  |  |   const file = new File(parts, filename, { type: "application/vnd.ms-excel" }); | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Binary Strings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Binary strings are strings where each character code is between `0` and `255`. | 
					
						
							|  |  |  | This structure is generated from the `FileReader#readAsBinaryString` method. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `read` method supports binary strings with `type: "binary"`. The | 
					
						
							|  |  |  | following snippet shows how `readAsBinaryString` can be paired with SheetJS: | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | // usage: file_bs_to_wb(file, function(wb) { /* wb is a workbook object */ }); | 
					
						
							|  |  |  | function file_bs_to_wb(file, callback) { | 
					
						
							|  |  |  |   var reader = new FileReader(); | 
					
						
							|  |  |  |   reader.onload = function(e) { | 
					
						
							|  |  |  |     /* e.target.result is a binary string */ | 
					
						
							|  |  |  |     callback(XLSX.read(e.target.result, { type: "binary" })); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   reader.readAsBinaryString(file); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The SheetJS `write` method can generate binary strings using `type: "binary"`: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | /* write workbook to binary string */ | 
					
						
							|  |  |  | const bstr = XLSX.write(wb, { bookType: "xlsx", type: "binary" }); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ### Base64 Strings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Base64 strings are encoded using 64 display ASCII characters. This structure is | 
					
						
							|  |  |  | generated from `btoa`, the `FileReader#readAsDataURL` method, and many platform | 
					
						
							|  |  |  | APIs in mobile and desktop app frameworks. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `read` method supports Base64 strings with `type: "base64"`. The | 
					
						
							|  |  |  | following snippet shows how `readAsDataURL` can be paired with SheetJS: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | ```js | 
					
						
							|  |  |  | // usage: file_b64_to_wb(file, function(wb) { /* wb is a workbook object */ }); | 
					
						
							|  |  |  | function file_b64_to_wb(file, callback) { | 
					
						
							|  |  |  |   var reader = new FileReader(); | 
					
						
							|  |  |  |   reader.onload = function(e) { | 
					
						
							|  |  |  |     /* e.target.result is a base64 string */ | 
					
						
							|  |  |  |     callback(XLSX.read(e.target.result, { type: "base64" })); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   reader.readAsDataURL(file); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The SheetJS `write` method can generate Base64 strings using `type: "base64"`: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | /* write workbook to Base64 string */ | 
					
						
							|  |  |  | const b64 = XLSX.write(wb, { bookType: "xlsx", type: "base64" }); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | ### Arrays of Numbers
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some platforms represent binary data as arrays of numbers, where each number | 
					
						
							|  |  |  | represents one byte in the file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS `read` method supports arrays of unsigned bytes (where each value | 
					
						
							|  |  |  | is between `0` and `255`) with `type: "array"`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution Java and Signed Bytes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [Google Sheets](/docs/demos/extensions/gsheet) follows Java signed data type | 
					
						
							|  |  |  | conventions. Byte arrays include values from `-128` to `127`. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>How to Fix Signed Arrays</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The unsigned value for a negative byte can be calculated with a bitwise AND | 
					
						
							|  |  |  | (`&`) operation against `0xFF`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const unsigned_byte = signed_byte & 0xFF; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For legacy platforms including [NetSuite](/docs/demos/cloud/netsuite) 2.0, the | 
					
						
							|  |  |  | bitwise AND assignment operator (`&=`) can rectify an array in place: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* convert a signed byte array to an unsigned byte array in place */ | 
					
						
							|  |  |  | for(var i = 0; i < array.length; ++i) array[i] &= 0xFF; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For modern platforms, the `Uint8Array` constructor understands signed bytes: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* copy data into a new Uint8Array */ | 
					
						
							|  |  |  | const u8 = new Uint8Array(array); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Web Browsers
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::warning pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Not all web APIs are supported in all browsers.  For example, Firefox does not | 
					
						
							|  |  |  | support the "File System Access API". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Even when a browser technically supports a web API, it may be disabled in the | 
					
						
							|  |  |  | client browser. Some APIs do not give any feedback. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | ### HTML5 Download Attribute
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _Writing Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `writeFile` will attempt a download in the browser using the attribute. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | XLSX.writeFile(wb, "SheetJS.xlsx"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Implementation Details</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Under the hood, it creates a special URL and clicks a link. The library method | 
					
						
							|  |  |  | includes a few workarounds for legacy browsers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | **`XLSX.writeFile(wb, "SheetJS.xlsx");`** is roughly equivalent to: | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | /* write data -- `writeFile` infers bookType from filename but `write` cannot */ | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | const u8 = XLSX.write(wb, { bookType: "xlsx", type: "buffer" }); | 
					
						
							|  |  |  | /* create Blob */ | 
					
						
							|  |  |  | const blob = new Blob([u8]); | 
					
						
							|  |  |  | /* create object URL */ | 
					
						
							| 
									
										
										
										
											2023-06-23 20:24:44 +00:00
										 |  |  | const url = URL.createObjectURL(blob); | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* create `A` DOM element */ | 
					
						
							|  |  |  | const a = document.createElement("a"); | 
					
						
							|  |  |  | /* set export file name */ | 
					
						
							|  |  |  | a.download = "SheetJS.xlsx"; | 
					
						
							|  |  |  | /* wire up the object URL to the DOM element */ | 
					
						
							|  |  |  | a.href = url; | 
					
						
							|  |  |  | /* add to the page */ | 
					
						
							|  |  |  | document.body.appendChild(a); | 
					
						
							|  |  |  | /* click the link */ | 
					
						
							|  |  |  | a.click(); | 
					
						
							|  |  |  | /* remove the element from the page */ | 
					
						
							|  |  |  | document.body.removeChild(a); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | :::caution Web Workers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `XLSX.writeFile` requires DOM access and will not work in a Web Worker! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The workaround is to generate the file data from the Worker (using `XLSX.write`) | 
					
						
							|  |  |  | and send the data back to the main context for the actual download action. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 11:21:37 +00:00
										 |  |  | ["Creating a Local File"](/docs/demos/bigdata/worker#creating-a-local-file) | 
					
						
							|  |  |  | includes a live demo. | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-13 10:04:30 +00:00
										 |  |  | #### Google Tag Manager
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Google Tag Manager is known to intercept and corrupt links. This issue will | 
					
						
							|  |  |  | manifest as UUID file names like `01234567-89ab-cdef-0123-456789abcdef` . | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For sites using GTM, it is recommended to patch `document.createElement` and | 
					
						
							|  |  |  | revert after performing the export. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>GTM Workaround</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-10-13 10:04:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The workaround is to ensure new `A` elements created by `document.createElement` | 
					
						
							|  |  |  | have the `target` attribute set to `_blank`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | After calling `writeFile`, the old version of the method should be restored. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="GTM Workaround" | 
					
						
							|  |  |  | /* preparation */ | 
					
						
							|  |  |  | document.createElement2 = document.createElement; | 
					
						
							|  |  |  | document.createElement = function(...args) { | 
					
						
							|  |  |  |   if(args.length == 1 && args[0].toLowerCase() == "a") { | 
					
						
							|  |  |  |     const a = document.createElement2("a"); | 
					
						
							|  |  |  |     a.target = "_blank"; | 
					
						
							|  |  |  |     return a; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return document.createElement2.call(this, ...args); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* export (XLSX.writeFile) */ | 
					
						
							|  |  |  | XLSX.writeFile(wb, "SheetJS.xlsx"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* cleanup */ | 
					
						
							|  |  |  | setTimeout(() => { | 
					
						
							|  |  |  |   document.createElement = document.createElement2; | 
					
						
							|  |  |  |   delete document.createElement2; | 
					
						
							|  |  |  | }, 1000); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | ### File API
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _Reading Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | In the `change` event of `<input type="file">`, the event object will have a | 
					
						
							|  |  |  | `target` property. The `files` property of `target` is a list of `File` objects. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | async function handleFileAsync(e) { | 
					
						
							|  |  |  |   /* get first file */ | 
					
						
							|  |  |  |   const file = e.target.files[0]; | 
					
						
							|  |  |  |   /* get raw data */ | 
					
						
							|  |  |  |   const data = await file.arrayBuffer(); | 
					
						
							|  |  |  |   /* data is an ArrayBuffer */ | 
					
						
							|  |  |  |   const workbook = XLSX.read(data); | 
					
						
							|  |  |  |   /* do something with the workbook here */ | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |   console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | input_dom_element.addEventListener("change", handleFileAsync, false); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | ### HTML Drag and Drop API
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _Reading Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The `dataTransfer` property of the `drop` event holds a list of `File` objects: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | /* suppress default behavior for drag and drop events */ | 
					
						
							|  |  |  | function suppress(e) { e.stopPropagation(); e.preventDefault(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* handle data from drop event */ | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | async function handleDropAsync(e) { | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |   suppress(e); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  |   /* get first file */ | 
					
						
							|  |  |  |   const f = e.dataTransfer.files[0]; | 
					
						
							|  |  |  |   /* get raw data */ | 
					
						
							|  |  |  |   const data = await f.arrayBuffer(); | 
					
						
							|  |  |  |   /* data is an ArrayBuffer */ | 
					
						
							|  |  |  |   const wb = XLSX.read(data); | 
					
						
							|  |  |  |   /* do something with the workbook here */ | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |   console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | drop_dom_element.addEventListener("drop", handleDropAsync, false); | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | drop_dom_element.addEventListener("dragover", suppress, false); | 
					
						
							|  |  |  | drop_dom_element.addEventListener("dragenter", suppress, false); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | ### File System Access API
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | :::warning Limited Browser Support | 
					
						
							| 
									
										
										
										
											2022-09-05 10:00:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | At the time of writing, browser support was fairly limited.  Chrome introduced | 
					
						
							|  |  |  | the feature in version 86.  Safari did not support File System Access API. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 03:59:48 +00:00
										 |  |  | :::caution pass | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | When this demo was last tested, Google Chrome did not add an entry to the | 
					
						
							|  |  |  | "Downloads" list. Nevertheless the actual file was written correctly. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 05:05:26 +00:00
										 |  |  | :::note Tested Deployments | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 05:05:26 +00:00
										 |  |  | This browser demo was tested in the following environments: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | | Browser     | Date       | | 
					
						
							|  |  |  | |:------------|:-----------| | 
					
						
							| 
									
										
										
										
											2024-04-08 03:55:10 +00:00
										 |  |  | | Chrome 122  | 2024-04-07 | | 
					
						
							| 
									
										
										
										
											2023-11-04 05:05:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Some lesser-used browsers do not support File System Access API: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | | Browser     | Date       | | 
					
						
							|  |  |  | |:------------|:-----------| | 
					
						
							| 
									
										
										
										
											2024-04-08 03:55:10 +00:00
										 |  |  | | Safari 17.4 | 2024-04-07 | | 
					
						
							|  |  |  | | Firefox 124 | 2024-04-07 | | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Live Example</b> (click to show) </summary> | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | This live example reads a file then tries to save as XLSX. If the File System | 
					
						
							|  |  |  | Access API is not supported, the result will be a clear message. | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```jsx live | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | function SheetJSRoundTripFileSystemAPI() { return window.showSaveFilePicker ? ( | 
					
						
							|  |  |  | <button onClick={async () => { | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |   /* Show picker and get data */ | 
					
						
							|  |  |  |   const [rFile] = await window.showOpenFilePicker({ | 
					
						
							|  |  |  |     types: [{ | 
					
						
							|  |  |  |       description: 'Spreadsheets', | 
					
						
							|  |  |  |       accept: { 'application/vnd.ms-excel': ['.xlsx', '.xls', '.xlsb', /*...*/] } | 
					
						
							|  |  |  |     }], | 
					
						
							|  |  |  |     excludeAcceptAllOption: true, | 
					
						
							|  |  |  |     multiple: false | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const ab = await (await rFile.getFile()).arrayBuffer(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* parse */ | 
					
						
							|  |  |  |   const wb = XLSX.read(ab); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Show picker and get handle to file */ | 
					
						
							|  |  |  |   const wFile = await window.showSaveFilePicker({ | 
					
						
							|  |  |  |     suggestedName: "SheetJSRT.xlsx", | 
					
						
							|  |  |  |     types: [ { description: 'XLSX', accept: { 'application/vnd.ms-excel': ['.xlsx'] } } ] | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const wstream = await wFile.createWritable(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* write */ | 
					
						
							|  |  |  |   const buf = XLSX.write(wb, { bookType: "xlsx", type: "buffer" }); | 
					
						
							|  |  |  |   wstream.write(buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* close stream to commit file */ | 
					
						
							|  |  |  |   wstream.close(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | }}>Click to read then save as XLSX</button> | 
					
						
							|  |  |  |   ) : ( <b>This browser does not support File System Access API</b> ); } | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | _Reading Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `window.showOpenFilePicker` shows a file picker and resolves to an array of | 
					
						
							|  |  |  | file handles. When `multiple: false` is set, the array has one element. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `getFile` method resolves to a `File` object whose data can be read with | 
					
						
							|  |  |  | the `arrayBuffer` method: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* Show picker and get data */ | 
					
						
							|  |  |  | const [hFile] = await window.showOpenFilePicker({ | 
					
						
							|  |  |  |   types: [{ | 
					
						
							|  |  |  |     description: 'Spreadsheets', | 
					
						
							|  |  |  |     accept: { 'application/vnd.ms-excel': ['.xlsx', '.xls', '.xlsb', /*...*/] } | 
					
						
							|  |  |  |   }], | 
					
						
							|  |  |  |   excludeAcceptAllOption: true, | 
					
						
							|  |  |  |   multiple: false | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | const ab = await (await hFile.getFile()).arrayBuffer(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* parse */ | 
					
						
							|  |  |  | const wb = XLSX.read(ab); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* do something with the workbook */ | 
					
						
							|  |  |  | console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Writing Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `window.showSaveFilePicker` shows a file picker and resolves to a file handle. | 
					
						
							|  |  |  | The `createWritable` method resolves to a `FileSystemWritableFileStream`, which | 
					
						
							|  |  |  | readily accepts `Uint8Array` data from `XLSX.write`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* Show picker and get handle to file */ | 
					
						
							|  |  |  | const hFile = await window.showSaveFilePicker({ | 
					
						
							|  |  |  |   suggestedName: "SheetJS.xlsx", | 
					
						
							|  |  |  |   types: [ | 
					
						
							|  |  |  |     { description: 'Excel 2007+ (XLSX)', accept: { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'] } }, | 
					
						
							|  |  |  |     { description: 'Excel 97-2004 (XLS)', accept: { 'application/vnd.ms-excel': ['.xls'] } }, | 
					
						
							|  |  |  |     { description: 'Excel 2007+ Binary (XLSB)', accept: { 'application/vnd.ms-excel.sheet.binary.macroEnabled.12': ['.xlsb'] } }, | 
					
						
							|  |  |  |     /* note that each MIME type must be unique! */ | 
					
						
							|  |  |  |   ] | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | const wstream = await hFile.createWritable(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* get extension */ | 
					
						
							|  |  |  | const ext = hFile.name.slice(hFile.name.lastIndexOf(".")+1) | 
					
						
							|  |  |  | /* write */ | 
					
						
							|  |  |  | wstream.write(XLSX.write(wb, { bookType: ext, type: "buffer" })) | 
					
						
							|  |  |  | /* close stream to commit file */ | 
					
						
							|  |  |  | wstream.close(); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | ### File and Directory Entries API
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 10:00:35 +00:00
										 |  |  | :::caution Deprecated | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In the web browser, the File and Directory Entries API has been deprecated and | 
					
						
							|  |  |  | is not recommended for new applications. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `cordova-plugin-file` still uses the API patterns. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _Writing Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The API is callback-based. At a high level: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) `window.requestFileSystem` requests access to the filesystem. The callback | 
					
						
							|  |  |  | receives a `FileSystem` object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) A file is created using the `getFile` method. The callback receives a | 
					
						
							|  |  |  | `FileSystemFileEntry` object representing the file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3) A writer is created using the `createWriter` method of the file object. The | 
					
						
							|  |  |  | callback receives a `FileWriter` object representing a file handle for writing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4) Data is written using the `write` method of the `FileWriter` object. Unlike | 
					
						
							|  |  |  | the other methods, callbacks are attached to the `FileWriter` object directly. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ```js | 
					
						
							|  |  |  | // Request File System Access | 
					
						
							|  |  |  | window.requestFileSystem(window.PERSISTENT, 0, (fs) => { | 
					
						
							|  |  |  |   // Request a handle to "SheetJS.xlsx", making a new file if necessary | 
					
						
							|  |  |  |   fs.root.getFile("SheetJS.xlsx", {create: true}, entry => { | 
					
						
							|  |  |  |     // Request a FileWriter for writing data | 
					
						
							|  |  |  |     entry.createWriter(writer => { | 
					
						
							|  |  |  |       // The FileWriter API needs an actual Blob | 
					
						
							|  |  |  |       const u8 = XLSX.write(wb, { type: "buffer", bookType: "xlsx" }); | 
					
						
							|  |  |  |       const data = new Blob([u8], { type: "application/vnd.ms-excel" }); | 
					
						
							|  |  |  |       // `onwriteend` is called on success, `onerror` called on error | 
					
						
							|  |  |  |       writer.onwriteend = () => {}; writer.onerror = () => {}; | 
					
						
							|  |  |  |       // write the data | 
					
						
							|  |  |  |       writer.write(data); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 03:44:38 +00:00
										 |  |  | ### Internet Explorer
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Internet Explorer offered proprietary APIs that were not adopted by Chromium. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Blob API
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Writing Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | IE10 and IE11 support `navigator.msSaveBlob`. `XLSX.writeFile` will use this | 
					
						
							|  |  |  | method if it is available. | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Implementation Details</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | **`XLSX.writeFile(wb, "SheetJS.xlsx");`** is roughly equivalent to: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* write data -- `writeFile` infers bookType from filename but `write` cannot */ | 
					
						
							|  |  |  | const u8 = XLSX.write(wb, { bookType: "xlsx", type: "buffer" }); | 
					
						
							|  |  |  | /* create Blob */ | 
					
						
							|  |  |  | const blob = new Blob([u8]); | 
					
						
							|  |  |  | /* call msSaveBlob */ | 
					
						
							|  |  |  | navigator.msSaveBlob(blob, "SheetJS.xlsx"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | #### VBScript
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _Reading and Writing Files_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Internet Explorer 6-9 with VBScript support `Scripting.FileSystemObject`.  This | 
					
						
							|  |  |  | is not supported in modern browsers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This approach is implemented in the library `readFile` and `writeFile` methods. | 
					
						
							|  |  |  | It requires the shim script to be loaded before the main library script: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```html | 
					
						
							|  |  |  | <!-- load the shim script first --> | 
					
						
							|  |  |  | <script src="shim.min.js"></script> | 
					
						
							|  |  |  | <!-- then load the main script --> | 
					
						
							|  |  |  | <script src="xlsx.full.min.js"></script> | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Other Platforms
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### NodeJS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `fs.readFileSync` and `fs.writeFileSync` allow for reading and writing files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When using `require`, these are supported in `readFile` and `writeFile`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var XLSX = require("xlsx"); | 
					
						
							|  |  |  | var wb = XLSX.readFile("sheetjs.numbers"); | 
					
						
							|  |  |  | XLSX.writeFile(wb, "sheetjs.xls"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | [Installation](/docs/getting-started/installation/nodejs) has a special note for | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | use with NodeJS ECMAScript Modules: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { readFile, writeFile, set_fs } from 'xlsx'; | 
					
						
							|  |  |  | import * as fs from 'fs'; | 
					
						
							|  |  |  | set_fs(fs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | var wb = readFile("sheetjs.numbers"); | 
					
						
							|  |  |  | writeFile(wb, "sheetjs.xlsx"); | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Implementation Details</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | **`XLSX.readFile(filepath)`** is equivalent to: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _CommonJS_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var fs = require("fs"); | 
					
						
							|  |  |  | var buf = fs.readFileSync(filepath); | 
					
						
							|  |  |  | var wb = XLSX.read(buf); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _ECMAScript Modules_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { read } from "xlsx"; | 
					
						
							|  |  |  | import { readFileSync } from "fs"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var buf = readFileSync(filepath); | 
					
						
							|  |  |  | var wb = read(buf); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **`XLSX.writeFile(wb, filepath)`** is equivalent to: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _CommonJS_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var fs = require("fs"), path = require("path"); | 
					
						
							|  |  |  | var buf = XLSX.write(wb, { bookType: path.extname(filepath).slice(1), type: "buffer" }); | 
					
						
							|  |  |  | fs.writeFileSync(filepath, buf); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _ECMAScript Modules_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { write } from "xlsx"; | 
					
						
							|  |  |  | import { writeFileSync } from "fs"; | 
					
						
							|  |  |  | import { extname } from "path"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var buf = write(wb, { bookType: extname(filepath).slice(1), type: "buffer" }); | 
					
						
							|  |  |  | writeFileSync(filepath, buf); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-30 22:12:52 +00:00
										 |  |  | ### ExtendScript
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In Photoshop and other Adobe apps, `readFile` and `writeFile` use the `File` | 
					
						
							|  |  |  | object under the hood: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | #include "xlsx.extendscript.js"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var wb = XLSX.readFile("sheetjs.xlsx"); | 
					
						
							|  |  |  | XLSX.writeFile(wb, "sheetjs.csv"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 22:09:08 +00:00
										 |  |  | The [ExtendScript demo](/docs/demos/extensions/extendscript) also covers "Common | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | Extensibility Platform" (CEP) and "Unified Extensibility Platform" (UXP) details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Chrome Extensions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In Manifest v2 Chrome extensions, `writeFile` calls `chrome.downloads.download`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This approach uses `URL.createObjectURL`, an API that is not supported in a | 
					
						
							|  |  |  | Manifest v3 Background Service Worker. For small exports, raw Base64 URLs can be | 
					
						
							|  |  |  | generated and downloaded. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The [Chromium demo](/docs/demos/extensions/chromium) covers the details. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ### Deno
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | `readFile` uses `Deno.readFileSync` and `writeFile` uses `Deno.writeFileSync`: | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 11:21:37 +00:00
										 |  |  | <CodeBlock language="ts">{`\ | 
					
						
							|  |  |  | // @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts" | 
					
						
							|  |  |  | import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'; | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | const wb: XLSX.WorkBook = XLSX.readFile("sheetjs.numbers"); | 
					
						
							|  |  |  | XLSX.writeFile(wb, "sheetjs.xlsx");`} | 
					
						
							|  |  |  | </CodeBlock> | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | :::caution Deno entitlements | 
					
						
							| 
									
										
										
										
											2022-09-02 05:52:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | Any Deno script using `XLSX.readFile` requires the `--allow-read` entitlement. | 
					
						
							| 
									
										
										
										
											2022-09-02 05:52:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | Any Deno script using `XLSX.writeFile` requires the `--allow-write` entitlement. | 
					
						
							| 
									
										
										
										
											2022-09-02 05:52:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Implementation Details</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | **`XLSX.readFile(filepath)`** is equivalent to: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _ECMAScript Modules_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CodeBlock language="ts">{`\ | 
					
						
							|  |  |  | // @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts" | 
					
						
							|  |  |  | import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'; | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | const u8: Uint8Array = Deno.readFileSync(filepath); | 
					
						
							|  |  |  | const wb: XLSX.WorkBook = XLSX.read(u8);`} | 
					
						
							|  |  |  | </CodeBlock> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **`XLSX.writeFile(wb, filepath)`** is equivalent to: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _ECMAScript Modules_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CodeBlock language="ts">{`\ | 
					
						
							|  |  |  | // @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts" | 
					
						
							|  |  |  | import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'; | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | const u8 = XLSX.write(wb, { bookType: filepath.slice(filepath.lastIndexOf(".")+1), type: "buffer" }); | 
					
						
							|  |  |  | Deno.writeFileSync(filepath, u8);`} | 
					
						
							|  |  |  | </CodeBlock> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 19:21:53 +00:00
										 |  |  | ### Bun
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Bun requires the `fs` module: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | import { readFile, writeFile, set_fs } from 'xlsx'; | 
					
						
							| 
									
										
										
										
											2022-08-26 19:21:53 +00:00
										 |  |  | import * as fs from 'fs'; | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | set_fs(fs); | 
					
						
							| 
									
										
										
										
											2022-08-26 19:21:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | var wb = readFile("sheetjs.numbers"); | 
					
						
							|  |  |  | writeFile(wb, "sheetjs.xlsx"); | 
					
						
							| 
									
										
										
										
											2022-08-26 19:21:53 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-06 10:01:12 +00:00
										 |  |  | The implementation is identical to [NodeJS ECMAScript Modules](#nodejs). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | ### Apps
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Desktop and mobile apps have their own specific APIs covered in separate demos: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | - [Electron and other desktop apps](/docs/demos/desktop) | 
					
						
							|  |  |  | - [React Native and other mobile apps](/docs/demos/mobile) | 
					
						
							| 
									
										
										
										
											2023-09-14 08:19:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | [^1]: See ["Input Type" in "Reading Files"](/docs/api/parse-options#input-type) | 
					
						
							|  |  |  | [^2]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats) | 
					
						
							|  |  |  | [^3]: See ["Buffers and TypedArrays"](https://nodejs.org/api/buffer.html#buffers-and-typedarrays) in the NodeJS documentation. |