web-dev-qa-db-fra.com

Comment enregistrer des données .xlsx dans un fichier en tant que blob

J'ai une question similaire à cette question ( Javascript: l'exportation d'un texte volumineux/d'un fichier csv bloque Google Chrome ):

J'essaie de sauvegarder les données créées par la fonction EB.createFile() de excelbuilder.js. Si je mets les données du fichier en tant que valeur d'attribut href d'un lien, cela fonctionne. Toutefois, lorsque les données sont volumineuses, le navigateur Chrome se bloque. Les codes sont comme ça: 

//generate a temp <a /> tag
var link = document.createElement("a");
link.href = 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,' + encodeURIComponent(data);
link.style = "visibility:hidden";
link.download = fileName;

document.body.appendChild(link);
link.click();
document.body.removeChild(link);

Mes codes pour créer les données en utilisant excelbuilder.js sont comme suit: 

var artistWorkbook = EB.createWorkbook();
var albumList = artistWorkbook.createWorksheet({name: 'Album List'});

albumList.setData(originalData); 

artistWorkbook.addWorksheet(albumList);

var data = EB.createFile(artistWorkbook);

Comme suggéré par la réponse à la question similaire ( Javascript: L’exportation de fichiers texte/csv de taille importante bloque Google Chrome ), un blob doit être créé. 

Mon problème est que ce qui est enregistré dans le fichier n'est pas un fichier Excel valide pouvant être ouvert par Excel. Les codes que j'utilise pour enregistrer la blob sont les suivants: 

var blob = new Blob(
    [data],
    {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,"}
);

// Programatically create a link and click it:
var a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = fileName;
a.click();

Si je remplace le [data] dans les codes ci-dessus par [Base64.decode(data)], le contenu du fichier enregistré ressemble davantage aux données Excel attendues, mais ne peut toujours pas être ouvert par Excel. 

Merci!

15
gm2008

J'ai eu le même problème que toi. Il s'avère que vous devez convertir le fichier de données Excel en un ArrayBuffer.

var blob = new Blob([s2ab(atob(data))], {
    type: ''
});

href = URL.createObjectURL(blob);

La méthode s2ab (que j'ai obtenue de https://github.com/SheetJS/js-xlsx/blob/master/README.md ) est:

function s2ab(s) {
  var buf = new ArrayBuffer(s.length);
  var view = new Uint8Array(buf);
  for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
  return buf;
}
19
Ron T

La réponse ci-dessus est correcte. Veuillez vous assurer que vous avez une chaîne de données en base64 dans la variable de données sans préfixe ou quelque chose comme ça, juste des données brutes. 

Voici ce que j'ai fait côté serveur (asp.net mvc core):

string path = Path.Combine(folder, fileName);
Byte[] bytes = System.IO.File.ReadAllBytes(path);
string base64 = Convert.ToBase64String(bytes);

Du côté client, j'ai fait le code suivant:

const xhr = new XMLHttpRequest();

xhr.open("GET", url);
xhr.setRequestHeader("Content-Type", "text/plain");

xhr.onload = () => {
    var bin = atob(xhr.response);
    var ab = s2ab(bin); // from example above
    var blob = new Blob([ab], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;' });

    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = 'demo.xlsx';

    document.body.appendChild(link);

    link.click();

    document.body.removeChild(link);
};

xhr.send();

Et cela fonctionne parfaitement pour moi.

5
Vitalii Bratok

essayez la bibliothèque FileSaver.js. cela pourrait aider.

https://github.com/eligrey/FileSaver.js/

2
Vyacheslav

Solution pour moi.

Étape 1

<a onclick="exportAsExcel()">Export to Excel</a>

Étape 2

J'utilise lib. Économiseur de fichier.

En savoir plus: https://www.npmjs.com/package/file-saver

npm i file-saver

Étape 3 

let FileSaver = require('file-saver'); // path to file-saver

function exportAsExcel() {
    let dataBlob = '...kAAAAFAAIcmtzaGVldHMvc2hlZXQxLnhtbFBLBQYAAAAACQAJAD8CAADdGAAAAAA='; // If have ; You should be split get blob data only
    this.downloadFile(dataBlob);
}

function downloadFile(blobContent){
    let blob = new Blob([base64toBlob(blobContent, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')], {});
    FileSaver.saveAs(blob, 'report.xlsx');
}

function base64toBlob(base64Data, contentType) {
    contentType = contentType || '';
    let sliceSize = 1024;
    let byteCharacters = atob(base64Data);
    let bytesLength = byteCharacters.length;
    let slicesCount = Math.ceil(bytesLength / sliceSize);
    let byteArrays = new Array(slicesCount);
    for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
        let begin = sliceIndex * sliceSize;
        let end = Math.min(begin + sliceSize, bytesLength);

        let bytes = new Array(end - begin);
        for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
            bytes[i] = byteCharacters[offset].charCodeAt(0);
        }
        byteArrays[sliceIndex] = new Uint8Array(bytes);
    }
    return new Blob(byteArrays, { type: contentType });
}

Travaille pour moi. ^^

0
bamossza

Cela fonctionne à partir de: v0.14.0 de https://github.com/SheetJS/js-xlsx

/* generate array buffer */
var wbout = XLSX.write(wb, {type:"array", bookType:'xlsx'});
/* create data URL */
var url = URL.createObjectURL(new Blob([wbout], {type: 'application/octet-stream'}));
/* trigger download with chrome API */
chrome.downloads.download({ url: url, filename: "testsheet.xlsx", saveAs: true });
0
David Dehghan