1

I am using Node.js with Express. I am trying to delete a file after sending it to client with express js.

function deleteFile (file) { 
    fs.unlink(file, function (err) {
        if (err) {
            logger.error(err);
        }
    });
}

app.get("/deleteFileAfterDownload", function (req, res){
    var fileName = "a.pdf"
    var stream = fs.createReadStream(fileName);
    var streamClosed = false;
    req.on('end',function(){ 
        if (!streamClosed){  
            stream.emit('close');
            // I tried stream.destroy() but that is also not working
        }
    });
    stream.on('close', function () {
        streamClosed = true; 
        deleteFile(fileName);
    });
    req.on('data', function(){});  
    stream.pipe(res);
});

But the file is not getting deleted. it seems the process is still using file because just after I end the process, the file is getting deleted.

Can anybody tell me why? If I am doing it wrong, please tell me a good way.

Harikrishnan
  • 3,664
  • 7
  • 48
  • 77
  • unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse. source: http://man7.org/linux/man-pages/man2/unlink.2.html – n32303 May 19 '16 at 11:18

1 Answers1

2

Please add a log in deleteFile, makesure it is called.

Try simplify it:

var fileName = "a.pdf"
var stream = fs.createReadStream(fileName);
stream.pipe(res);
res.once("finish", function () {
    deleteFile(fileName);
});

The previous example only delete file if download finished, if you want delete file unconditionly, try the following:

var fileName = "a.pdf";
var stream = fs.createReadStream(fileName);
stream.pipe(res).once("close", function () {
    stream.close();
    deleteFile(fileName);
});

stream.close() is important here, because stream not close if pipe aborted.

tangxinfa
  • 1,410
  • 13
  • 12
  • Thank you very much for answering. I put log in deleteFile. The function is getting called. But the res.once function is not getting called when client aborts connection. on successful completion it is called. – Harikrishnan May 19 '16 at 10:27
  • If you need makesure file is deleted even if request is aborted, you can use "close" event instead of "finish" event on res. Or call deleteFile(filename) directly after stream.pipe(res), this can avoid multiple user download the same file concurrently, when stream closed the underlayer file is deleted from filesystem. – tangxinfa May 19 '16 at 11:41
  • But the stream is not closed if the client is not reading. even if client closes the connection the stream is not closing, and hence the file is not deleted. When I stop the server, it closes stream and files are getting deleted. – Harikrishnan May 20 '16 at 04:41
  • stream not close if pipe aborted, please take a look at the next code snipet in the modified answer. – tangxinfa May 20 '16 at 12:41
  • i created a gist, please have a look: https://gist.github.com/tangxinfa/ceaf31d8c14231617cf05dc7a6b2555c – tangxinfa May 20 '16 at 12:58
  • Thanks for the answer. The solution worked for me. But instead of stream.close I had to write stream.destroy since the Node gave me an exception saying close is not a function. – Harikrishnan May 21 '16 at 03:01
  • Which node version you use? stream.destroy is the same as stream.close, is not documented, but exist on fs.ReadStream, i checked node-v0.12.7 and node-v4.4.4 source code. see related discuss: http://stackoverflow.com/questions/19277094/how-to-close-a-readable-stream-before-end – tangxinfa May 21 '16 at 06:30