4

The frontend of the application having a file download option (which can be in the following format: xlsx, csv, dat). For that, I use fileSaver.js

Everything works fine for the format .dat/.csv but for the .xlsx it does not work the files are corrupted.

I tested the conversion with the following formats :

  • utf8
  • base64
  • binary

Here's how I do :

// /* BACK */ //
// data is 
fs.readFile(filePath, (err, data) {...})

// the api give this answer the important part is "filename" & "data"
{"status":"ok","context":"writing the intermediate file","target":"/temp/","fileName":"name.xlsx","data":{"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]}}
// /* FRONT */ //
let json = JSON.stringify(data)
let buffer = Buffer.from(JSON.parse(json).data)
let read = buffer.toString('utf8')
let blob = new Blob([read])
FileSaver.saveAs(blob, fileName)
BPDESILVA
  • 2,040
  • 5
  • 15
  • 35
Hadock
  • 796
  • 1
  • 12
  • 28

3 Answers3

1

Ok for anybody who pass in this topic, my solution :

(keep in mind the real better solution for dl a file : send file in api response with header 'Content-disposition' or use express for that like this)

The back (Node) work like this :

 fs.readFile(filePath, (err, data) => {
    if (err) {
      console.log(`-------- oups error - read --------`)
      console.log(err)
      res.send({ status: `erreur`, context: `read the source file`, id: err.errno, code: err.code, message: err.message.replace(/\\/g, '/') })
    } else {
      res.send({ status: `ok`, context: `send data file`, target: target, fileName: fileName, data: data })
    } 
  })

Here :

  • target is the path for the front with the name of the file and his extension (/path/name.ext)
  • fileName is juste the name and the extension (name.ext)
  • data is the data send by the readFile ({"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]})

The front (React) work like this :

fetch(targetUrl)
    .then(res => res.json())
    .then(res => {
      if (res.status !== `ok`) {
        this.setState({
          errorDlFile: true,
          errorDlFile_context: res.context,
          errorDlFile_id: res.id,
          errorDlFile_code: res.code,
          errorDlFile_message: res.message
        })
      } else {  
        const target = res.target
        const fileName = res.fileName
        const data = res.data
        const splitName = res.fileName.split('.')
        const format = splitName[splitName.length-1]

        // file saver blob solution
        let json = JSON.stringify(data)
        let buffer = Buffer.from(JSON.parse(json).data)
        let readUTF8 = buffer.toString('utf8')
        let blob = ''

        if (format === 'xlsx') {
          blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
        } else if (format === 'csv') {
          blob = new Blob([readUTF8], { type: 'application/vnd.ms-excel' })
        } else {
          blob = new Blob([readUTF8])
        }

        FileSaver.saveAs(blob, fileName)

      }
    })
Hadock
  • 796
  • 1
  • 12
  • 28
0

@Hadock if you want to download file with .csv extension then you need to pass the type of file like

let blob = new Blob([csv], { type: 'application/vnd.ms-excel' });

instead of

let blob = new Blob([read])

and don't forgot to send filename with extension (test.csv).

For excel file I used different plugin exceljs demo.

Rishabh Garg
  • 706
  • 1
  • 9
  • 28
  • It's good for .csv, but not for .xlsx. I add some details in my post like the JSON that is sent by my backend. I read your example, but I do not understand how I should store the data in the file. – Hadock Jun 20 '19 at 11:17
  • @Hadock Create a plunker, I will help you to generate excel file. – Rishabh Garg Jun 20 '19 at 11:28
0

you can't save json data directly to .xlsx file, you can convert json data to excel format using library like 'sheetjs' (https://sheetjs.com/)

var ws_name = filename;//"SheetJS";
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), filename + ".xlsx")
Shiyas
  • 46
  • 5
  • why is ``sheet_from_array_of_arrays`` and ``s2ab`` I can't import them and I don't see them in the sheetjs doc – Hadock Jun 20 '19 at 12:12
  • Ok the correct path is ``XLSX.utils.sheet_add_aoa(data)`` and ``XLSX.utils.s2ab(wbout)``. Anyway my data is not a ``aoa`` is a buffer ``[72,82,65,67,67,69,83,83,32,10]`` – Hadock Jun 20 '19 at 12:36