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)
});
}
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.
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);
}
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();
});
Related
I am working with react. I have a file to download. and its download to browser default save location(Download folder)
FileSaver.saveAs(res.data, fileTitle + "." + fileExtension);
I have found that its not possible to change with FileSaver.saveAs method. So i want to know is there a another method in react to save file to local path.
You can't save a file to a particular path using FileSaver library.
But there's a new File System API you can use to achieve that. There's a project by googlechromelabs, a simple text editor (demo), designed to experiment with and demonstrate the new File System Access APIs.
Create a new file.
To save a file, call showSaveFilePicker(), which shows the file picker in "save" mode, allowing the user to pick a new file they want to use for saving
async function getNewFileHandle() {
const options = {
types: [
{
description: 'Text Files',
accept: {
'text/plain': ['.txt'],
},
},
],
};
const handle = await window.showSaveFilePicker(options);
return handle;
}
Save changes to disk
// fileHandle is an instance of FileSystemFileHandle..
async function writeFile(fileHandle, contents) {
// Create a FileSystemWritableFileStream to write to.
const writable = await fileHandle.createWritable();
// Write the contents of the file to the stream.
await writable.write(contents);
// Close the file and write the contents to disk.
await writable.close();
}
I'm trying to re-upload/move a file is already existed in firebase storage to another path in the same firebase Storage with different folder and changing its name using redux-actions, so the file getting uploaded but it corrupted => it means when I try to open it, it's opening with no data/picture and the size of the picture 9B
the code:
// upload the same file with new path and remove the old file
let uploadAndDeletePromises = fileArr.map(
(fileData, index) =>
storageRef
// newpaths=folderName/FolderWithIdName/fileName__docId.png
.child(newFilesPaths[index])
.put(
// filesToUpload data showed in the pictures below
filesToUpload[index],
// metadata={customMetadata:
// {uplaoderId:"",PrId:""}
metadata[index]
)
.then(() =>
//remove old path
storageRef
// fileData.path -> the old path
// FolderName/folderWithIdName/fileName.png
.child(fileData.path)
.delete()
)
);
return Promise.all(uploadAndDeletePromises);
the result from the filesToUpload from the original one which works well, these are when the first time I upload:
the result from the filesToUpload from the one which I want to re-upload from firebase storage to another path in firestore storage, these are when the I'm trying to re-upload to different path:
Anyone experience handling/moving a file from a path to another and changing its name, using react js actions, firebase storage, not node js.
The functions to move a file are in the server-side libraries. If you want to move a file in the client you'll have to take the following steps:
1. Download the file
2. Upload the file to the new location
3. Delete the previous file (if required)
It looks like you have an idea as to how to upload the new file and delete the previous one, but are having problems downloading the previous file (which is why a 9B file is uploading).
As per the documentation, you would download the file like this
storageRef.child('path/to/file').getDownloadURL()
.then((url) => {
// `url` is the download URL for the file
// This can be downloaded directly:
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = (event) => {
var blob = xhr.response;
// insert upload and delete code here
};
xhr.open('GET', url);
xhr.send();
})
.catch((error) => {
// Handle any errors
});
I'm trying to make a help command that when you use it, instead of having to manually type all the commands, how would I do that? like if I do !help utility how would I grab the utility folder and then get all the commands and list it? i've been trying fs but its confusing with how you would get directs. any help?
You're on the right track with using fs
const fs = require('fs')
// check if that folder exists
if (!fs.existsSync(`../../commands/${args[0]}`))
return message.channel.send('That folder does not exist');
// make array of all files within this folder
const files = fs.readdirSync(`../../commands/${args[0]})
for (const file of files) {
const command = require(`../../commands/${args[0]}/${file}`) // require the file
// now you can do whatever you want with it!
console.log(command.name, command.desription)
};
I'm having a hard time translating from Node.js to Appengine #google-cloud/storage.
To verify if a folder is up-to-date I go through some simple steps:
check if folder exist. If not, return false, if yes ->
check the files if they have the right name
In regular javascript, goes like this and works without problems:
if (!fs.existsSync(full_path)) {
return false;
}
else {
// else verify if all requiered files exist
let check = true;
let files = fs.readdirSync(full_path);
allExpectedFiles.forEach((f) => {
if (pfs.pfs.getFileName('pictures') !== f && files.indexOf(f) === -1) {
// console.log(c.cyan, 'Not found file: ' + f);
check = false;
}
});
return check;
}
Using #google-cloud/storage library... I just can't make it work.
I tried:
// if folder does not exist:
const dir = bucket.file(full_path);
let doesExist = await dir.exists();
console.info('For:', name, ' does folder exist?:',full_path, doesExist[0]);
if (!doesExist[0]) {
// folder does not exist so it's not uptodate
return false;
}
I got false even for thous who do exist.
Note 1: If I check with a file (adding the file name instead of ending in "/"), it works. But I need to check the folder.
Also, I tried to get the files from the folder (forcing true for folders by checking for file) and I can't get them either.
let files = await bucket.getFiles({prefix: full_path, delimiter:'.json'});
console.log(c.magenta,'Here are the files:');
console.log(files);
I got nothing. I played with prefix and delimiter but I just can't get them to work.
Note 2: I did read: How subdirectories works, but... obviously I can't get it.
Any suggestions? I'm aware that this should be a very simple task, I just can't make it work.
Later edit:
I manage to get the files but only as "all/the/long/path/filename.json". I can live with it, I'll extract the file name but it seems something is wrong, it can't be that difficult. Here is my code:
let files = await bucket.getFiles({
prefix : full_path
});
files = files[0];
files.forEach((f)=>{
console.log(c.magenta, 'Fisierele cele multe:', f.name);
});
There really are no directories in the Cloud Storage. They're just emulated based on the file paths.
So just skip the steps for checking if the destination directory exists and creating it and just go directly to checking the files in the "directory", building their file paths based on the source directory that you want to check.
I am trying to download a tar.gz file from server which gets created at run time. Here is the code at the server side
function downloadFile(req, res) {
//some code to generate the tar file
var file = ... code to compute the path ...
res.download(file);
}
The method which calls this from the client side looks like this
continueWithApplication(app) {
this.$http.get('/api/applications/get-agent/' + app._id + '/' + this.nodeName).then(res => {
var data = new Blob([res.data], { type: 'application/x-gzip' });
this.FileSaver.saveAs(data, 'agent-1.0.tar.gz');
})
.catch(err => {
alert('error downloading agent.');
});
}
I am using angular-file-saver to get the file downloaded.
I can see the file getting downloaded but when i try to untar the file it doesn't untar the content but creates a file with .cpgz extension. I have verified that the file that gets generated at server side is a valid .tar.gz file by unzipping it. Below screeen shot shows what happens when i try to untar the dowaloaded file (agent-1.0.tar.tar.gz -> agent-1.0.tar.gz.cpgz)
Any idea what am i doing wrong? Any pointer is deeply appreciated.
P.S. Please pardon my limited knowledge of angular and mean stack.