From 22720fd7a6db931d2e914844e7c818910bbcd81b Mon Sep 17 00:00:00 2001 From: SheetJS Date: Wed, 19 Oct 2022 17:12:12 -0400 Subject: [PATCH] nits --- docz/docs/03-demos/04-grid.md | 2 +- docz/docs/03-demos/07-worker.md | 18 ++- docz/docs/03-demos/33-localfile.md | 199 +++++++++++++++++++---------- 3 files changed, 142 insertions(+), 77 deletions(-) diff --git a/docz/docs/03-demos/04-grid.md b/docz/docs/03-demos/04-grid.md index 470030c..e65f544 100644 --- a/docz/docs/03-demos/04-grid.md +++ b/docz/docs/03-demos/04-grid.md @@ -202,7 +202,7 @@ many additional features including massive data streaming, sorting and styling. ### Tabulator -[Tabulator](http://tabulator.info/docs/5.3/download#xlsx) includes deep support +[Tabulator](https://tabulator.info/docs/5.4/download#xlsx) includes deep support through a special Export button. It handles the SheetJS operations internally. diff --git a/docz/docs/03-demos/07-worker.md b/docz/docs/03-demos/07-worker.md index 5d1f50d..43aa263 100644 --- a/docz/docs/03-demos/07-worker.md +++ b/docz/docs/03-demos/07-worker.md @@ -100,7 +100,8 @@ In the following example, the script: - generates a workbook object in the Web Worker - generates a XLSB file using `XLSX.write` in the Web Worker -- sends the file (`Uint8Array`) to the main browser context +- generates an object URL in the Web Worker +- sends the object URL to the main browser context - performs a download action in the main browser context ```jsx live @@ -124,11 +125,14 @@ SheetJS,in,Web,Workers 1,2,3,4\`; const wb = XLSX.read(csv, { type: "string" }); - /* Write XLSB data */ + /* Write XLSB data (Uint8Array) */ const u8 = XLSX.write(wb, { bookType: "xlsb", type: "buffer" }); + /* Generate URL */ + const url = URL.createObjectURL(new Blob([u8])); + /* Reply with result */ - postMessage({data: u8}); + postMessage({ url }); } catch(e) { /* Pass the error message back */ postMessage({error: String(e.message || e).bold() }); @@ -142,7 +146,7 @@ SheetJS,in,Web,Workers /* this mantra is the standard HTML5 download attribute technique */ const a = document.createElement("a"); a.download = "SheetJSWriteFileWorker.xlsb"; - a.href = URL.createObjectURL(new Blob([e.data.data])); + a.href = e.data.url; document.body.appendChild(a); a.click(); document.body.removeChild(a); @@ -176,10 +180,10 @@ In the following example, the script: ```jsx live function SheetJSDragDropWorker() { const [html, setHTML] = React.useState(""); - /* suppress default behavior for dragover and drop */ + /* suppress default behavior for drag and drop */ function suppress(e) { e.stopPropagation(); e.preventDefault(); } return ( <> -
{ +
{ suppress(e); /* this mantra embeds the worker source in the function */ @@ -188,7 +192,7 @@ function SheetJSDragDropWorker() { importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"); /* this callback will run once the main context sends a message */ -self.addEventListener('message', async(e) => { +self.addEventListener('message', (e) => { try { /* Read file data */ const ab = new FileReaderSync().readAsArrayBuffer(e.data.file); diff --git a/docz/docs/03-demos/33-localfile.md b/docz/docs/03-demos/33-localfile.md index 6e11b9f..6f7004f 100644 --- a/docz/docs/03-demos/33-localfile.md +++ b/docz/docs/03-demos/33-localfile.md @@ -2,10 +2,11 @@ title: Local File Access --- -Reading and writing files require native support. `readFile` and `writeFile` -include support for some approaches but do not support every API. When an API -is not supported by `readFile` or `writeFile`, the underlying `read` and -`write` methods can be used. +Reading and writing files require native platform support. `XLSX.readFile` and +`XLSX.writeFile` include support for some APIs. + +For other APIs, user code can pass data to `XLSX.read` or use data generated by +`XLSX.write` directly. Both methods work with a number of common storage types. This demo looks at various web APIs. More specific approaches for deployments like mobile apps are covered in their respective demos. @@ -35,20 +36,63 @@ Modern browser APIs typically use typed arrays or `Blob` or `File` structures. _Reading Binary Data_ -Given a `Blob` or `File`, the underlying data cannot be read synchronously! +`XLSX.read` supports `Uint8Array` and `ArrayBuffer` data. For `Blob` or `File` +objects, the underlying data must be pulled into an `ArrayBuffer`. The callback-based approach uses a `FileReader`: ```js -const reader = new FileReader(); -reader.onload = function(e) { - /* e.target.result is an ArrayBuffer */ - const wb = XLSX.read(e.target.result); - console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); +// 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); } -reader.readAsArrayBuffer(file); ``` +
FileReaderSync in Web Workers (click to show) + +`FileReaderSync` is only available in Web Workers: + +```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 */ +}); +``` + +["User-Submitted File" example](./worker#user-submitted-file) has a live demo. + +
+ +
IE10 Binary Strings (click to show) + +In IE10, binary strings are more performant than `ArrayBuffer`. `XLSX.read` +supports binary strings with `type: "binary"`: + +```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); +} +``` + +
+ The Promise-based approach uses `Blob#arrayBuffer`: ```js @@ -60,8 +104,9 @@ async function blob_to_wb(blob) { _Writing Binary Data_ -`XLSX.write` can generate `Uint8Array` results by passing `type: "buffer"`. A -`Blob` can be created by using the constructor: +`XLSX.write` can generate `Uint8Array` results by passing `type: "buffer"`. + +A `Blob` can be created by using the constructor: ```js const u8 = XLSX.write(workbook, { type: "buffer", bookType: "xlsx" }); @@ -78,6 +123,17 @@ _Writing Files_ XLSX.writeFile(wb, "SheetJS.xlsx"); ``` +:::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. + +["Creating a Local File" includes a live demo](./worker#creating-a-local-file). + +::: + ## File API _Reading Files_ @@ -93,7 +149,7 @@ async function handleFileAsync(e) { /* data is an ArrayBuffer */ const workbook = XLSX.read(data); /* do something with the workbook here */ - console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])) + console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])); } input_dom_element.addEventListener("change", handleFileAsync, false); ``` @@ -105,8 +161,12 @@ _Reading Files_ The `dataTransfer` property of the `drop` event holds a list of files: ```js +/* suppress default behavior for drag and drop events */ +function suppress(e) { e.stopPropagation(); e.preventDefault(); } + +/* handle data from drop event */ async function handleDropAsync(e) { - e.stopPropagation(); e.preventDefault(); + suppress(e); /* get first file */ const f = e.dataTransfer.files[0]; /* get raw data */ @@ -114,9 +174,12 @@ async function handleDropAsync(e) { /* data is an ArrayBuffer */ const wb = XLSX.read(data); /* do something with the workbook here */ - console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])) + console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])); } + drop_dom_element.addEventListener("drop", handleDropAsync, false); +drop_dom_element.addEventListener("dragover", suppress, false); +drop_dom_element.addEventListener("dragenter", suppress, false); ``` ## File System Access API @@ -128,6 +191,45 @@ the feature in version 86. Safari did not support File System Access API. ::: +
Live Example (click to show) + +This live example reads a file then tries to save as XLSX. + +```jsx live +function SheetJSRoundTripFileSystemAPI() { return ( ) } +``` + +
+ _Reading Files_ `window.showOpenFilePicker` shows a file picker and resolves to an array of @@ -182,47 +284,6 @@ wstream.write(XLSX.write(wb, { bookType: ext, type: "buffer" })) wstream.close(); ``` -### Demo - -
Live Example (click to show) - -This live example reads a file then tries to save as XLSX. - -```jsx live -function SheetJSRoundTripFileSystemAPI() { return ( ) } -``` - -
- ## File and Directory Entries API :::caution Deprecated @@ -263,7 +324,8 @@ Internet Explorer offered proprietary APIs that were not adopted by Chromium. _Writing Files_ -IE10 and IE11 support `navigator.msSaveBlob`. `writeFile` will use the method. +IE10 and IE11 support `navigator.msSaveBlob`. `XLSX.writeFile` will use this +method if it is available. #### VBScript @@ -304,8 +366,8 @@ import { readFile, writeFile, set_fs } from 'xlsx'; import * as fs from 'fs'; set_fs(fs); -var wb = XLSX.readFile("sheetjs.numbers"); -XLSX.writeFile(wb, "sheetjs.xlsx"); +var wb = readFile("sheetjs.numbers"); +writeFile(wb, "sheetjs.xlsx"); ``` ### ExtendScript @@ -322,8 +384,7 @@ XLSX.writeFile(wb, "sheetjs.csv"); ### Deno -`Deno.readFileSync` and `Deno.writeFileSync` are supported by `readFile` and -`writeFile` out of the box: +`readFile` uses `Deno.readFileSync` and `writeFile` uses `Deno.writeFileSync`: ```js // @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts" @@ -333,11 +394,11 @@ const wb = XLSX.readFile("sheetjs.numbers"); XLSX.writeFile(wb, "sheetjs.xlsx"); ``` -:::note +:::caution Deno entitlements -Any script using `XLSX.readFile` requires the `--allow-read` permission. +Any Deno script using `XLSX.readFile` requires the `--allow-read` entitlement. -Any script using `XLSX.writeFile` requires the `--allow-write` permission. +Any Deno script using `XLSX.writeFile` requires the `--allow-write` entitlement. ::: @@ -346,12 +407,12 @@ Any script using `XLSX.writeFile` requires the `--allow-write` permission. Bun requires the `fs` module: ```js -import * as XLSX from 'xlsx'; +import { readFile, writeFile, set_fs } from 'xlsx'; import * as fs from 'fs'; -XLSX.set_fs(fs); +set_fs(fs); -var wb = XLSX.readFile("sheetjs.numbers"); -XLSX.writeFile(wb, "sheetjs.xlsx"); +var wb = readFile("sheetjs.numbers"); +writeFile(wb, "sheetjs.xlsx"); ``` ### Apps