11 KiB
title |
---|
Local File Access |
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.
:::note
Some snippets are also available in the "Common Use Cases" section:
:::
:::warning
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.
:::
Binary Data
Modern browser APIs typically use typed arrays or Blob
or File
structures.
Reading Binary Data
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
:
// 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);
}
FileReaderSync in Web Workers (click to show)
FileReaderSync
is only available in Web Workers:
// 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 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"
:
// 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
:
// usage: const wb = await blob_to_wb(blob);
async function blob_to_wb(blob) {
return XLSX.read(await blob.arrayBuffer());
}
Writing Binary Data
XLSX.write
can generate Uint8Array
results by passing type: "buffer"
.
A Blob
can be created by using the constructor:
const u8 = XLSX.write(workbook, { type: "buffer", bookType: "xlsx" });
const blob = new Blob([u8], { type: "application/vnd.ms-excel" });
HTML5 Download Attribute
Writing Files
writeFile
will attempt a download in the browser using the attribute.
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.
:::
File API
Reading Files
In the change
event of <input type="file">
, target
hold a list of files:
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 */
console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
}
input_dom_element.addEventListener("change", handleFileAsync, false);
HTML Drag and Drop API
Reading Files
The dataTransfer
property of the drop
event holds a list of files:
/* suppress default behavior for drag and drop events */
function suppress(e) { e.stopPropagation(); e.preventDefault(); }
/* handle data from drop event */
async function handleDropAsync(e) {
suppress(e);
/* 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 */
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
:::caution Limited Browser Support
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.
:::
Live Example (click to show)
This live example reads a file then tries to save as XLSX.
function SheetJSRoundTripFileSystemAPI() { return ( <button onClick={async () => {
/* 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();
}}>Click to read then save as XLSX</button> ) }
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:
/* 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
:
/* 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();
File and Directory Entries API
:::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.
:::
Writing Files
// 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);
});
});
});
Internet Explorer
Internet Explorer offered proprietary APIs that were not adopted by Chromium.
Blob API
Writing Files
IE10 and IE11 support navigator.msSaveBlob
. XLSX.writeFile
will use this
method if it is available.
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:
<!-- 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
:
var XLSX = require("xlsx");
var wb = XLSX.readFile("sheetjs.numbers");
XLSX.writeFile(wb, "sheetjs.xls");
Installation has a special note for use with NodeJS ECMAScript Modules:
import { readFile, writeFile, set_fs } from 'xlsx';
import * as fs from 'fs';
set_fs(fs);
var wb = readFile("sheetjs.numbers");
writeFile(wb, "sheetjs.xlsx");
ExtendScript
In Photoshop and other Adobe apps, readFile
and writeFile
use the File
object under the hood:
#include "xlsx.extendscript.js"
var wb = XLSX.readFile("sheetjs.xlsx");
XLSX.writeFile(wb, "sheetjs.csv");
Deno
readFile
uses Deno.readFileSync
and writeFile
uses Deno.writeFileSync
:
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
const wb = XLSX.readFile("sheetjs.numbers");
XLSX.writeFile(wb, "sheetjs.xlsx");
:::caution Deno entitlements
Any Deno script using XLSX.readFile
requires the --allow-read
entitlement.
Any Deno script using XLSX.writeFile
requires the --allow-write
entitlement.
:::
Bun
Bun requires the fs
module:
import { readFile, writeFile, set_fs } from 'xlsx';
import * as fs from 'fs';
set_fs(fs);
var wb = readFile("sheetjs.numbers");
writeFile(wb, "sheetjs.xlsx");
Apps
Desktop and mobile apps have their own specific APIs covered in separate demos: