Ziv-Barber / officegen

Standalone Office Open XML files (Microsoft Office 2007 and later) generator for Word (docx), PowerPoint (pptx) and Excell (xlsx) in javascript. The output is a stream.
MIT License
2.65k stars 471 forks source link

Error: ENOENT: no such file or directory, unlink './sample1.xlsx' #330

Open dougbm opened 4 years ago

dougbm commented 4 years ago

Environment

  1. node -v: v12.5.0
  2. npm -v: 6.9.0
  3. npm ls officegen: officegen@0.6.3
  4. Operating system: Windows 10
  5. Microsoft Office version: Office 2016
  6. Problem with Powerpoint, Excel or Word document: Powerpoint

Steps to Reproduce

  1. Clone https://github.com/dougbm/poc-pptgen-officegen (I am using the sample code from website
  2. npm install
  3. node index.js

Expected Behavior

Generate Powerpoint file

Actual Behavior

The below error is returned.

C:\Users\User\workspace\poc-pptgen-officegen$ node index.js
fs.js:126
    throw err;
    ^

Error: ENOENT: no such file or directory, unlink './sample1.xlsx'
    at Object.unlinkSync (fs.js:976:3)
    at C:\Users\User\workspace\poc-pptgen-officegen\node_modules\officegen\lib\core\index.js:490:16
    at Array.forEach (<anonymous>)
    at generateNextResource (C:\Users\User\workspace\poc-pptgen-officegen\node_modules\officegen\lib\core\index.js:482:31)
    at officegen.generate (C:\Users\User\workspace\poc-pptgen-officegen\node_modules\officegen\lib\core\index.js:507:7)
    at Object.<anonymous> (C:\Users\User\workspace\poc-pptgen-officegen\index.js:53:6)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12) {
  errno: -4058,
  syscall: 'unlink',
  code: 'ENOENT',
  path: './sample1.xlsx'
}
ghaithtroudi commented 4 years ago

I had the same issue today with officegen@0.6.3 and windows 7

ghaithtroudi commented 4 years ago

After some digging, it looks like the problem is related to the slide.addChart() method

I think it is related to the fact that it is giving a link that is not working on windows using : genobj.options.tempDir = './'

in officegen/lib/pptx/genpptx.js

I tried backtracking the error but i cannot exactly follow the logic.

estani commented 4 years ago

Same thing here with linux. Just copied the pptx example and got an error about the missing excel file?! This is caused by the chart which apparently works by embedding an excel sheet or something like that. In any case it looks quite broken:

{ name: 'ppt\\embeddings\\Microsoft_Excel_Worksheet1.xlsx',
  type: 'file',
  data: './sample1.xlsx',
  callback: [Function: cbMakeChartDataExcel],
  is_perment: false,
  removed_after_used: true }

The name looks like a windows relative path, data is definitely a relative path pointing to whatever that got never created. Remove the chart you might have something that works.

The project doesn't seem to be alive anymore, though. I'll try another one,

dsample commented 4 years ago

I get the same issue on OSX. I've tried setting tempDir and I still get the error. When I watch the directory, nothing ever gets created, so of course it can't delete the file.

The code I've got is simple:

async function generatePowerpoint(filename, data) {
  return new Promise((resolve, reject) => {
    const pptx = officegen({ type: 'pptx', tempDir: __dirname + '/.tmp/'})
    const out = fs.createWriteStream(filename)

    pptx.on('error', (err) => {
      console.error(err)
      reject(err)
    })

    out.on('error', (err) => {
      console.error(err)
      reject(err)
    })

    pptx.on('finalize', (written) => {
      console.log('Powerpoint file written')
      resolve()
    })

    // out.on('finish', () => {
    //   console.log('Powerpoint file closed')
    //   resolve()
    // })  })

    const slide = pptx.makeNewSlide()
    slide.name = 'Foo'
    slide.addChart({
      title: 'Bar',
      renderType: 'pie',
      data: [{
        name: 'Wibble',
        labels: ['a','b','c'],
        values: [1,2,3],
      }]
    })

    pptx.generate(out)
  })
}

I tried commenting out the fs.unlinkSync line, and then it fails when something else is trying to read it

Error: ENOENT: no such file or directory, open '....../.tmp/sample1.xlsx'
Emitted 'error' event on ReadStream instance at:
    at internal/fs/streams.js:132:12
    at FSReqCallback.oncomplete (fs.js:154:23)
Ziv-Barber commented 4 years ago

The project doesn't seem to be alive anymore, though

The project is alive, but more on the background. I wrote it years ago and I'm working to clean all the mess inside it, add (real) unit tests, better documentation and examples. That's why I'm not responding much lately. Sorry about it. I'm just want to do it right.

dsample commented 4 years ago

@Ziv-Barber Any ideas where the underlying issue with this bug lies? I might be able to dig around some more, but any clues would be helpful.

Ziv-Barber commented 4 years ago

Sorry about the late response but this is how to do it multi-platform (Windows, Linux, OS-X):

Just set your temp directory to path.resolve(___dirname, '.tmp')

WARNING: DON'T do path.resolve(___dirname, '/.tmp') since that it will return '/.tmp'!

Now, this temporary path MUST be exists and with the permission to write into it. You can use node's built in either fs.mkdirSync or fs.mkdir to create the folder, or even better to use the external node module mkdirp.

dsample commented 4 years ago

Just set your temp directory to path.resolve(___dirname, '.tmp')

That doesn't work, and is actually worse than than the code I posted above.

With my code:

    const pptx = officegen({ type: 'pptx', tempDir: __dirname + '/.tmp/'})

the error is: that it can't delete the file <my_project_directory>/.tmp/sample1.xlsx, as there is nothing to delete, but it is attempting to delete a file in the .tmp directory within my project, which is good (the directory already exists)

Using path.resolve:

    const pptx = officegen({ type: 'pptx', tempDir: path.resolve(__dirname, '.tmp')})

the error I now get is that it can't find <my_project_directory>/.tmpsample1.xlsx. As you can see, it now doesn't have the final directory / in the path. However, it should still technically work, but it results in the same error, that it can't delete a file which never existed.

Ziv-Barber commented 4 years ago

There are two ways to "fix" this:

The no additional library way:

const fs = require('fs')

const tempDir = path.resolve(__dirname,. '/.tmp/')
if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir)

const pptx = officegen({ type: 'pptx', tempDir})

If will work if the parent directory exists and you are trying to create one level. So in your case it'll work (but refer also to the comments at the end of this post).

The better way:

Use node-mkdirp!

const tempDir = path.resolve(__dirname,. '/.tmp/')
const mkdirp = require('mkdirp')

mkdirp.sync(tempDir)

const pptx = officegen({ type: 'pptx', tempDir})

Warning:

Don't use __dirname for your temporary files! The best way to create a temporary folder is:

const fs = require('fs')
const { sep } = require('path')

const tempDir = fs.mkdtempSync(`${os.tmpdir()}${sep}`)
const pptx = officegen({ type: 'pptx', tempDir})

For more information please refer to the fs documentation.

So which of them you should use?

Depend....

tarunrao541 commented 8 months ago

@dsample / @Ziv-Barber

I am facing the same issue on node 16 using https://www.npmjs.com/package/officegen. I don't see this issue node 12. What could be the root cause?

jiaowenbo commented 3 months ago

Error: ENOENT: no such file or directory, open '/var/folders/lx/jb11wr6132388lvwgr0f0kw80000gn/T/1M9q7csample1.xlsx' Emitted 'error' event on ReadStream instance at: at emitErrorNT (node:internal/streams/destroy:157:8) at emitErrorCloseNT (node:internal/streams/destroy:122:3) at processTicksAndRejections (node:internal/process/task_queues:83:21) { errno: -2, code: 'ENOENT', syscall: 'open', path: '/var/folders/lx/jb11wr6132388lvwgr0f0kw80000gn/T/1M9q7csample1.xlsx' }@ @ @Ziv-Barber 三种方式都试了 还是有问题