0

In my project I have a table of projects. For each project there is a column for downloading pdf file. Now I want to be able to download all files and to create a single .rar file. There is a code for downloading a single file:

routes.js

app.get('/api/download/archive/:filename', function(req,res){
    res.download("public/uploads/"+req.params.filename, req.params.filename);
}) 

archive.js

$scope.downloadPdf = function(obj){
    $http.get('api/download/archive/'+obj.Documentation)
    .success(function(data){
        window.open('api/download/archive/'+obj.Documentation)
    });
}
R. Richards
  • 24,603
  • 10
  • 64
  • 64
Vitali
  • 341
  • 1
  • 5
  • 19
  • I think this package may help you.... https://www.npmjs.com/package/rar-to-zip – Parth Raval May 29 '18 at 10:36
  • The `.success` method is [deprecated and removed from V1.6](https://stackoverflow.com/questions/35329384/why-are-angular-http-success-error-methods-deprecated-removed-from-v1-6/35331339#35331339). – georgeawg May 29 '18 at 11:12
  • See also, [Binary files corrupted - How to Download Binary Files with AngularJS](https://stackoverflow.com/questions/41672656/binary-files-corrupted-how-to-download-binary-files-with-angularjs/41681589?s=1|61.6845#41681589). – georgeawg May 29 '18 at 11:14

3 Answers3

1

Unfortunately, RAR is a closed-source software. So the only way to create an archive is to install the command-line utility called rar and then use rar a command in a child process to compress the files.

To install rar on Mac I had to run brew install homebrew/cask/rar. You can find the installation instructions for other platforms here.

After you install it you can make use of child_process like this:

const { exec } = require('child_process');
const { promisify } = require('util');
const fs = require('fs');
const path = require('path');

// Promisify `unlink` and `exec` functions as by default they accept callbacks
const unlinkAsync = promisify(fs.unlink);
const execAsync = promisify(exec);

(async () => {
    // Generating a different name each time to avoid any possible collisions
    const archiveFileName = `temp-archive-${(new Date()).getTime()}.rar`;
    // The files that are going to be compressed.
    const filePattern = `*.jpg`;

    // Using a `rar` utility in a separate process
    await execAsync(`rar a ${archiveFileName} ${filePattern}`);

    // If no error thrown the archive has been created
    console.log('Archive has been successfully created');

    // Now we can allow downloading it

    // Delete the archive when it's not needed anymore
    // await unlinkAsync(path.join(__dirname, archiveFileName));

    console.log('Deleted an archive');
})();

In order to run the example please put some .jpg files into the project directory.

PS: If you choose a different archive format (like .zip) you would be able to make use of something like archiver for example. That might allow you to create a zip stream and pipe it to response directly. So you would not need to create any files on a disk. But that's a matter of a different question.

Antonio Narkevich
  • 4,206
  • 18
  • 28
  • Thank you for your answer(example doesn't work). I was able to create a .rar file with archiver ( https://archiverjs.com/docs/). I have changed .zip ->.rar and it created a rar file. – Vitali May 30 '18 at 13:08
  • My example creates an archive and then immediately delets it. :) Please comment out the unlink line. Also please make sure that `rar` is installed AND you have some .jpg files in the directory. Please let me know if it worked. @Vitali – Antonio Narkevich May 30 '18 at 13:12
  • @Vitali Also most likely `archiver` used the .zip algorithm. The file is just called .rar but it is still a zip archive. – Antonio Narkevich May 30 '18 at 13:13
  • @ Antonio Narkevich I can't find installation instruction for windows – Vitali May 30 '18 at 13:31
  • @Vitali Mostly likely if you just inwallt WinRAR and then try `rar` in the command line it's gonna be there. Could you try? Will do some googling though. – Antonio Narkevich May 30 '18 at 13:33
  • @Vitali Yeah, it seems that you need to install WinRAR and then add it to the PATH. Please see: https://www.youtube.com/watch?v=nvtzNAMpU2I – Antonio Narkevich May 30 '18 at 13:36
0

Try WinrarJs.
The project lets you Create a RAR file, Read a RAR file and Extract a RAR archive.

Here's the sample from GitHub:

/* Create a RAR file */

var winrar = new Winrar('/path/to/file/test.txt');
// add more files
winrar.addFile('/path/to/file/test2.txt');
// add multiple files
winrar.addFile(['/path/to/file/test3.txt', '/path/to/file/test4.txt']);

// set output file
winrar.setOutput('/path/to/output/output.rar');

// set options
winrar.setConfig({
    password: 'testPassword',
    comment: 'rar comment',
    volumes: '10',  // split volumes in Mega Byte
    deleteAfter: false, // delete file after rar process completed
    level: 0 // compression level 0 - 5
});

// archiving file
winrar.rar().then((result) => {
    console.log(result);
}).catch((err) => {
    console.log(err);
}
SNag
  • 17,681
  • 10
  • 54
  • 69
0

Unfortunately Nodejs dosn't native support Rar compression/decompression, i frustated with this too so i created a module called "super-winrar" making super easy deal with rar files in nodejs :)

check it out: https://github.com/KiyotakaAyanokojiDev/super-winrar

Exemple creating rar file "pdfs.rar" and appending all pdf files into:

const Rar = require('super-winrar');

const rar = new Rar('pdfs.rar');
rar.on('error', error => console.log(error.message));

rar.append({files: ['pdf1.pdf', 'pdf2.pdf', 'pdf3.pdf']}, async (err) => {
  if (err) return console.log(err.message);
  console.log('pdf1, pdf2 and pdf3 got successfully put into rar file!');
  rar.close();
});
Ayanokoji
  • 1
  • 2