Zip all files in a folder and download the zipped file - google-apps-script

I want to do the following:
a) zip all files inside a folder which is defined by its folder Id and return the FileId of the zipped archive
b) Create a download link from the zip's File Id so i can embed the link into my Html template so i can let users (with the right permissions to the shared drive where the .zip file is stored) download it by clicking on the link.
Now i am stuck with a)
My code so far is derived from this post: Creating a zip file inside Google Drive with Apps Script
But it seems like some of the solutions there are deprecated (f.ex. DocsList).
As i could not find up-to-date solutions from the recent 2 years that work for me i thought that it is worth to look now into the zipping case.
/*****
*** This Function returns all blobs from a folder
*/
function getBlobs(folderId) {
let blobs = [];
folder = DriveApp.getFolderById(folderId)
let files = folder.getFiles();
while (files.hasNext()) {
let file = files.next().getBlob();
blobs.push(file);
return blobs;
}
}
/*****
*** This Function zips all blobs in a folder and returns the zip file ID
*/
function zipFilesInFolder(blobs, filename) {
let zip = Utilities.zip(blobs, filename + '.zip');
zipFileId = zip.getId()
Logger.log("{zipFilesInFolder} [zipFileId]: " + zipFileId)
return zipFileId;
}
filename = "myzip"
folderId = "123456789a94..."
blobs = getBlobs(folderId)
zipFileId = zipFilesInFolder(blobs, filename)

THANK YOU Tanaike!
i fixed my code after following your kind suggestions:
/*****
*** This Function returns all blobs from a folder
*/
function getBlobs(folderId) {
let blobs = [];
// Get the folder containing the files to be zipped by its folderId
folder = DriveApp.getFolderById(folderId)
// Get the files from that folder
let files = folder.getFiles();
// Iterate through the files and add each ones to the array of blobs
while (files.hasNext()) {
let file = files.next().getBlob();
blobs.push(file);
}
return blobs;
}
/*****
*** This Function zips all blobs in a folder and returns the zip file ID
*/
function zipFilesInFolder(folderId, blobs, filename) {
// Get the folder containing the files to be zipped by its folderId
folder = DriveApp.getFolderById(folderId)
let zipped = Utilities.zip(blobs, filename + '.zip');
// Create the .zip Archive File and in the parent folder
// of the folder containing the files which were zipped
// and return its FileId
zippedFile = folder.getParents().next().createFile(zipped);
zipFileId = zippedFile.getId();
Logger.log("{zipFilesInFolder} [zipFileId]: " + zipFileId)
return zipFileId;
}
And now the a) part works like a charm! Thank you for your fast reply!

Related

Google Apps Script Unzipping Files - Issues

I have a script that looks in a destination folder and unzips files to a new folder. All works perfect as long as the zip contains just one file; anymore and I only seem to unzip the first file.
Im pretty sure the line that's causing this is which is picking the first record in the array of files however I am not quite skilful enough to figure out how to get around this. Any help would be greatly appreciated
[var newDriveFile = DestinationFolder.createFile(unZippedfile[0]);]
//Unzips all ZIP files in the folder
function Unzip() {
//Add folder ID to select the folder where zipped files are placed
var SourceFolder = DriveApp.getFolderById("14vRNV3FZJicplxeurycsfBHmETrUQBex")
//Add folder ID to save the where unzipped files to be placed
var DestinationFolder = DriveApp.getFolderById("1OJXkPrUqcqapsv366oCV_ZsvaECstKTn")
//Select the Zip files from source folder using the Mimetype of ZIP
var ZIPFiles = SourceFolder.getFilesByType(MimeType.ZIP)
//var ZIPFiles = SourceFolder.getFilesByName('MTTR.zip')
//Loop over all the Zip files
while (ZIPFiles.hasNext()){
// Get the blob of all the zip files one by one
var fileBlob = ZIPFiles.next().getBlob();
//Use the Utilities Class to unzip the blob
var unZippedfile = Utilities.unzip(fileBlob);
//Unzip the file and save it on destination folder
var newDriveFile = DestinationFolder.createFile(unZippedfile[0]); //I think this line is where my issue is
}
Logger.log("Finished Unzipping files")
}
As what Rodrigo mentioned in the comments, you need to loop it on all the files. unZippedfile.length is the number of files in the zip file. Use a loop around the createFile method.
Code:
// loop to all zip files
while (ZIPFiles.hasNext()){
var fileBlob = ZIPFiles.next().getBlob();
var unZippedfile = Utilities.unzip(fileBlob);
// loop to all items inside the current zip file
for (i=0; i<unZippedfile.length; i++) {
var newDriveFile = DestinationFolder.createFile(unZippedfile[i]);
}
}
Output:
Note:
Sample output above show the unzipped files on the same directory as I instantiated both source and destination with the same directory ID.

How to search and get a specific file using Google Apps Script to search in the Parent folder and in its subfolders?

The issue I'm current facing is:
I created a main folder named "Parent" with the folder ID:eg abcde12345.
Within the Parent folder, there are 3 diff folders (eg. Folder A, Folder B, Folder C) with their own files.
The specific file I am looking for is: "File to be sent.pdf"
This file, I placed in Folder C for example.
However, the script I wrote below (with some details edited out) only search for the specific file in the Parent folder. The search does not go into Folder A,B or C to look for the file with the exact filename.
Is there a way to search for this specific file within the Parent + A + B + C without hardcode the Folder A,B,C IDs in the script?
Thank you!
Ps. The number of sub folders may grow more than A,B,C and in these sub folders, I am thinking of creating more layers.
function ReturnWork(){
var markedFolder = DriveApp.getFolderById("abcde12345");
var ws = SpreadsheetApp.getActiveSpreadsheet();
/*This section which I edited out to shorten this post contains variables example:
-emailAddress
-subject
-etc... all details needed for the mailApp below.*/
var docName = 'File to be sent.pdf';
var markedFiles = markedFolder.getFilesByName(docName);
if(markedFiles.hasNext()){
MailApp.sendEmail({
to: emailAddress,
subject: subjectMarked,
replyTo: centre_email,
htmlBody : markedHTML.evaluate().getContent(),
attachments: [markedFiles.next().getAs(MimeType.PDF)],
});
}
}
One option would be to recursively search the file in the target folder and its subfolders:
function searchFileTest() {
const targetFolderId = 'abc123';
const fileName = 'File to be sent.pdf';
const filesFound = searchFile(fileName, targetFolderId);
for (const file of filesFound) {
Logger.log('File found: ' + file.getUrl());
}
}
function searchFile(fileName, folderId) {
let files = [];
// Look for file in current folder
const folderFiles = DriveApp.getFolderById(folderId).getFiles();
while (folderFiles.hasNext()) {
const folderFile = folderFiles.next();
if (folderFile.getName() === fileName) {
files.push(folderFile);
}
}
// Recursively look for file in subfolders
const subfolders = DriveApp.getFolderById(folderId).getFolders();
while (subfolders.hasNext()) {
files = files.concat(searchFile(fileName, subfolders.next().getId()));
}
return files;
}
This will return an array with all the files that have that name in the folder you specify of its subfolders.
Related:
How to search contents of files in all folders and subfolders of google drive in Apps Scripts?
Google apps script - iterate folder and subfolder
assign hyperlink to cell in google sheets to google drive files using google app script

Do not make copy of existing file in destination folder

I've been trying to copy contents from one folder to another folder in google drive using google app script. With some online help and documentation of google script, I was able to copy files from one folder to other but it copies all files from source folder to destination folder on time trigger, but I want only the new files to get copied in my destination folder and skip the present files that are already same in my source and destination folder.
I tried to check files by name before copying but couldn't find a way to compare files by name in two different folders of gdrive.
function CopyFiles() {
var SourceFolder = DriveApp.getFolderById('Sid');
var SourceFiles = DriveApp.getFolderById('Sid').getFiles();
var DestFolder = DriveApp.getFolderById('Did');
var DestFiles = DriveApp.getFolderById('Did').getFiles();
while (SourceFiles.hasNext())
{
var files = SourceFiles.next();
var dfiles = DestFiles.next();
if ( files == dfiles){
file.setTrashed(true);}
else{
var f = files.makeCopy(DestFolder);
}
}
}
What I want to achieve is that Script compares files by name in destination folder and if files by that name already exist than skip else, create a copy of that new file in the destination folder.
Copies files from source to destination if destination does have the same file names
In this version no files get trashed.
function CopyFiles() {
var srcFldr=DriveApp.getFolderById('srcId');
var srcFiles=srcFldr.getFiles();
var desFldr=DriveApp.getFolderById('desId');
var desFiles=desFldr.getFiles();
var dfnA=[];
while(desFiles.hasNext()) {
var df=desFiles.next();
dfnA.push(df.getName());
}
while(srcFiles.hasNext()) {
var sf=srcFiles.next();
if(dfnA.indexOf(sf.getName())==-1) {
sf.makeCopy(sf.getName(),desFldr);
}
}
}

Download Folder as Zip Google Drive API

I currently have a Google App Script in Google Sheet that gives me the URL of a folder, which I can then use to download. Though it is an extra step I would like to remove, and get the URL of the zipped content directly.
Here's my code (google app script):
function downloadSelectedScripts() {
// ...
var scriptFiles = getScriptFiles(scriptFileNames)
var tempFolder = copyFilesToTempFolder(scriptFiles)
Browser.msgBox(tempFolder.getUrl())
}
function copyFilesToTempFolder(files) {
var tempFolder = DriveApp.getFolderById(FOLDERS.TEMP)
var tempSubFolder = tempFolder.createFolder('download_' + Date.now())
for (var i in files) {
var file = files[i]
file.makeCopy(file.getName(), tempSubFolder)
}
return tempSubFolder
}
You want to compress all files in a folder as a zip file.
The folder has no subfolders.
All files are only text files.
The total size of all files is less than 50 MB.
You want to retrieve the URL for downloading the zip file.
If my understanding is correct, how about this sample script? The flow of this script is as follows.
Retrieve folder.
Retrieve blobs of all files in the folder.
Compress blobs and retrieve a blob of zip.
Create a zip blob as a file.
Retrieve URL for downloading.
Sample script:
When you use this script, please set the folder ID of folder that you want to compress.
function myFunction() {
var folderId = "###"; // Please set the folder ID here.
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFiles();
var blobs = [];
while (files.hasNext()) {
blobs.push(files.next().getBlob());
}
var zipBlob = Utilities.zip(blobs, folder.getName() + ".zip");
var fileId = DriveApp.createFile(zipBlob).getId();
var url = "https://drive.google.com/uc?export=download&id=" + fileId;
Logger.log(url);
}
Result:
The direct link of the zip file is returned as follows.
https://drive.google.com/uc?export=download&id=###
Note:
In the current stage, unfortunately, the folders cannot be included in the zip data with Google Apps Script.
In this sample script, the filename of zip file is the folder name. So please modify it for your situation.
If you want to download the zip file without login to Google, please share the file.
Reference:
zip(blobs, name)

Specify folder to save files to in Google Script

I have a simple form published through Google Apps Scripts that lets someone upload a file anonymously. The script works well, but it will always save to the root of my Google Drive instead of to a specific folder. I'd like it to create a new folder with the person's first name + last name (collected from the form) within a specific folder. I know I need to use the destination FolderID, just not sure how to use it properly.
Here's my existing code:
function uploadFiles(form) {
try {
var dropbox = form.FirstName + form.LastName;
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.Name);
return "Thank you, your file was uploaded successfully!";
I'm not sure if I understood well what is your goal. But if you want to create folder 'FirstnameLastname' within some specific folder, you should first select this 'parent' folder and then use it for creating new one.
EDIT:
Summary
First look at the reference from Google. You use class DriveApp and methode .createFolder(). Google cheat sheet says, that this methode within the DriveApp class 'Creates a folder in the root of the user's Drive with the given name.'. This methode returns folder as return type (your variable type will be folder).
This is the reason why your code creates folders only in root folder.
Look in the cheatsheet again but now look at the folder class. You can use the same methode .createFolder() with this class. Result is following: 'Creates a folder in the current folder with the given name.' This methode returns again folder.
Solution
Google Drive:
Create (or open) manually your desired folder in your Google Drive repository.
Find the ID of your folder (when you open the folder, you can find the id at the end of the URL: drive.google.com/drive/folders/{this is your ID})
Script:
Get your desired destination folder var parentFolder = DriveApp.getFolderById("{put your folder id here}");
Add your code
When you are creating new folder within parent folder, just call the .createFolder() methode from your parentFolder which you have created earlier: var folder = parentFolder.createFolder();
Edited script:
function uploadFiles(form) {
try {
var dropbox = form.FirstName + form.LastName;
var parentFolder = DriveApp.getFolderById('parentfolderId'); //add this line...
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = parentFolder.createFolder(dropbox); //edit this line
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.Name);
return "Thank you, your file was uploaded successfully!";
}