I'm trying to read a CSV Excel file using exceljs and multer for the file upload.
#Post('excel')
#UseInterceptors(FileInterceptor('excel'))
async uploadFile(#UploadedFile() file: Express.Multer.File) {
const workBook = new Excel.Workbook();
await workBook.csv
.read(createReadStream(file.buffer))
.catch((err) => console.log('err'));
const sheet = workBook.getWorksheet('Sheet1');
const cellValue = sheet.getRow(0).getCell(1).value;
return cellValue;
}
But I am getting the Error: ENOENT: no such file or directory
Instead of read, you have to use load
workBook.xlsx.load(file.buffer)
Related
I'm a beginners with Node.JS... I created a .Json file from a .csv with the 'csvtojson module' but I can't find out how save the Json in a global variable in order to use it... Could someone help me?
const CSVToJSON = require('csvtojson');
const fs = require('fs');
// convert users.csv file to JSON array
CSVToJSON().fromFile('flyers_data.csv')
.then( flyers_data => {
console.log(flyers_data);
}).catch(err => {
// log error if any
console.log(err);
});
in nodejs you can require .json file directly to use :
// foo.json
{
"bar":"buzz"
}
in js:
let fooFile = require("/path/to/foo.json")
console.log(fooFile)
console.log(foorFile.bar)
I am using exceljs library in my angular/electron project and I am trying to save a new updated excel file but an error occurred.
my code:
const workbook = new Excel.Workbook();
const data = await fs.promises.readFile('item.xlsx');
const wb = await workbook.xlsx.load(data.buffer);
const worksheet = wb.getWorksheet('Order');
const buffer = await wb.xlsx.writeBuffer();
const blob = new Blob([buffer]);
FileSaver.saveAs(blob, `${Date.now()}.xlsx`);
any suggestions.
I have web appication that can upload excel file. If user upload, the app should parse it and will return some rows that file have. So, The application don't need to save file to its filesystem. Parsing file and return rows is a job. But below code, I wrote this morning, it save file to its server and then parse it.. I think it's waste server resource.
I don't know how to read excel file with createReadStream. Without saving file, how can I parse excel directly? I am not familiar with fs, of course, I can delete file after the job finished, but is there any elegant way?
import { createWriteStream } from 'fs'
import path from 'path'
import xlsx from 'node-xlsx'
// some graphql code here...
async singleUpload(_, { file }, context) {
try {
console.log(file)
const { createReadStream, filename, mimetype, encoding } = await file
await new Promise((res) =>
createReadStream()
.pipe(createWriteStream(path.join(__dirname, '../uploads', filename)))
.on('close', res)
)
const workSheetsFromFile = xlsx.parse(path.join(__dirname, '../uploads', filename))
for (const row of workSheetsFromFile[0].data) {
console.log(row)
}
return { filename }
} catch (e) {
throw new Error(e)
}
},
Using express-fileupload library which provides a buffer representation for uploaded files (through data property), combined with excel.js which accepts a buffers will get you there.
see Express-fileupload and Excel.js
// read from a file
const workbook = new Excel.Workbook();
await workbook.xlsx.readFile(filename);
// ... use workbook
// read from a stream
const workbook = new Excel.Workbook();
await workbook.xlsx.read(stream);
// ... use workbook
// load from buffer // this is what you're looking for
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data);
// ... use workbook
Here's a simplified example:
const app = require('express')();
const fileUpload = require('express-fileupload');
const { Workbook } = require('exceljs');
app.use(fileUpload());
app.post('/', async (req, res) => {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
// The name of the input field (i.e. "myFile") is used to retrieve the uploaded file
await new Workbook().xlsx.load(req.files.myFile.data)
});
app.listen(3000)
var xlsx = require('xlsx')
//var workbook = xlsx.readFile('testSingle.xlsx')
var workbook = xlsx.read(fileObj);
You just need to use xlsx.read method to read a stream of data.
you can add an event listener before you pipe the data, so you can do something with your file before it uploaded, it look like this
async singleUpload(_, { file }, context) {
try {
console.log(file)
const { createReadStream, filename, mimetype, encoding } = await file
await new Promise((res) =>
createReadStream()
.on('data', (data)=>{
//do something with your data/file
console.log({data})
//your code here
})
.pipe(createWriteStream(path.join(__dirname, '../uploads', filename)))
.on('close', res)
)
},
you can see the documentation
stream node js
I am facing some errors while I try to save the csv files in another folder under the documents directory in the electron app. It only happens when i try to use relative paths but does not occur if i try to save in the same documents directory. so i have read a number of error no such file directory in nodejs applications and tried them but I am not having any success. i am interested in electron app on window machine.
Failed to export the csv file [Error: ENOENT: no such file or directory, open 'C:\Users\hellomachine\Documents\invoicer\Expenses.csv'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'C:\\Users\\hellomachine\\Documents\\invoicer\\Expenses.csv'
}
This is the code that I have tried utilising but no success.
//const exportFolder = app.getPath('documents') //this works well since they are in same directory
const exportFolder = `${app.getPath('documents')}/invoicer`;//this fails as there is relative paths or directory
//let csvFilePath = __dirname(`${exportFolder}/${fileName}.csv`) //this failed to write the file
//let csvFilePath = exportFolder + `/invoicer/${fileName}.csv`
let csvFilePath = exportFolder + `/${fileName}.csv`
//fs.writeFile(csvFilePath, csvData, (err)=>{
fs.writeFile(path.join(__dirname, csvFilePath), csvData, (err)=>{
if (err) {
console.log('Failed to export the csv file', err)
}
console.log('successful exported the csv file')
})
After alot of debugging on windows, it is better to first create the sub directory in the documents folder and then you can write the csv file there.
const exportFolder = path.join(app.getPath('documents'), './invoicer/');
//solution is to first create the above sub directory if it does not exist.
const timeSubDirectory = `${exportFolder}/${generateTimeBasedSubDirectory()}`
fs.mkdir( timeSubDirectory, {recursive:true}, function(err){
if (err) {
reject('Failed to create the export sub directory' + err)
}
exportArray.forEach((item,i)=>{
let fileName = timeSubDirectory + `/${item.group}.csv` //csv file
createCSVFile(fileName, item.groupItems)
if (i === lastItem) {
resolve('Completed exporting all files')
}
})
})
function createCSVFile(fileName, csvData){
fs.writeFile(fileName, csvData, (err)=>{
if (err) {
console.log('Failed to export the csv file', err)
}
console.log('successful exported the csv file')
})
}
This is my code for writing and downloading excel file using exceljs.
const excel = require('exceljs')
const tempfile = require('tempfile')
var workbook = new excel.Workbook()
var sheet1 = workbook.addWorksheet('sample')
sheet1.columns = req.keys // Some data
var tempFilePath = tempfile('.csv')
workbook.csv.writeFile(tempFilePath).then(function() {
res.download(tempFilePath, 'sample.csv', function(err) {
if (err) {
res.status(500).json({
"success": false,
"error": err
})
return
}
})
})
When i replace csv to xlsx, it writes but the file is corrupted.
const excel = require('exceljs')
const tempfile = require('tempfile')
var workbook = new excel.Workbook()
var sheet1 = workbook.addWorksheet('sample')
sheet1.columns = req.keys // Some data
var tempFilePath = tempfile('.xlsx')
workbook.xlsx.writeFile(tempFilePath).then(function() {
res.download(tempFilePath, 'sample.xlsx', function(err) {
if (err) {
res.status(500).json({
"success": false,
"error": err
})
return
}
})
})
Have attached the snapshots of it here.
csv file | Unreadable image | Corrupted image | Postman response
Try adding Content-Type header:
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
CSV file's format is raw text, so it is easy to read without caring about MIME type. xlsx format is more complicated. If you don't set the content-type, the browser won't know what to do with the file
I solved the problem. Hope this helps you.
If you download this excel file from the server side (In my case Node JS).
The problem is solved by one line on the client side: req.responseType = "arraybuffer";
requestData(req, "exportToExcel")
.then(resXHR => {
// For the correct processing of data from the server, you must specify the format/structure of data transfer
resXHR.responseType = "arraybuffer"
// Wait until the data is downloaded from the server
resXHR.onload = function () {
// Call a modal window for saving with type and file name
saveAs(new Blob([resXHR.response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), 'users.xlsx')
}
})