14
votes

I have a folder in Google Drive folder containing few files. I want to make a Google Apps Script that will zip all files in that folder and create the zip file inside same folder.

I found a video that has Utilities.zip() function, but there is no API reference for that. How do I use it? Thanks in advance.

5
I see there is now an API Reference for that. developers.google.com/apps-script/reference/utilities/…ChrisJJ
Any progress on this? Any working method?Dan

5 Answers

14
votes

Actually it's even easier than that. Files are already Blobs (anything that has getBlob() can be passed in to any function that expects Blobs). So the code looks like this:

var folder = DocsList.getFolder('path/to/folder');
folder.createFile(Utilities.zip(folder.getFiles(), 'newFiles.zip'));

Additionally, it won't work if you have multiple files with the same name in the Folder... Google Drive folders support that, but Zip files do not.

To make this work with multiple files that have the same name:

var folder = DocsList.getFolder('path/to/folder');
var names = {};
folder.createFile(Utilities.zip(folder.getFiles().map(function(f){
  var n = f.getName();
  while (names[n]) { n = '_' + n }
  names[n] = true;
  return f.getBlob().setName(n);
}), 'newFiles.zip'));
12
votes

As DocsList has been deprecated, You can use the following code to zip an entire folder containing files and sub-folders and also keep its structure:

var folder = DriveApp.getFolderById('<YOUR FOLDER ID>');
var zipped = Utilities.zip(getBlobs(folder, ''), folder.getName()+'.zip');
folder.getParents().next().createFile(zipped);

function getBlobs(rootFolder, path) {
  var blobs = [];
  var files = rootFolder.getFiles();
  while (files.hasNext()) {
    var file = files.next().getBlob();
    file.setName(path+file.getName());
    blobs.push(file);
  }
  var folders = rootFolder.getFolders();
  while (folders.hasNext()) {
    var folder = folders.next();
    var fPath = path+folder.getName()+'/';
    blobs.push(Utilities.newBlob([]).setName(fPath)); //comment/uncomment this line to skip/include empty folders
    blobs = blobs.concat(getBlobs(folder, fPath));
  }
  return blobs;
}

getBlobs function makes an array of all files in the folder and changes each file name to it's relative path to keep structure when became zipped.

To zip a folder containing multiple items with the same name use this getBlob function:

function getBlobs(rootFolder, path) {
  var blobs = [];
  var names = {};
  var files = rootFolder.getFiles();
  while (files.hasNext()) {
    var file = files.next().getBlob();
    var n = file.getName();
    while(names[n]) { n = '_' + n }
    names[n] = true;
    blobs.push(file.setName(path+n));
  }
  names = {};
  var folders = rootFolder.getFolders();
  while (folders.hasNext()) {
    var folder = folders.next();
    var n = folder.getName();
    while(names[n]) { n = '_' + n }
    names[n] = true;
    var fPath = path+n+'/';
    blobs.push(Utilities.newBlob([]).setName(fPath)); //comment/uncomment this line to skip/include empty folders
    blobs = blobs.concat(getBlobs(folder, fPath));
  }
  return blobs;
}
2
votes

I was able to use the code that @Hafez posted but I needed to modify it because It was not working for me. I added the first three lines because I needed the folder ID which is a string value and is not the name of the folder.

var folderName = DriveApp.getFoldersByName("<folderName>");
var theFolder = folderName.next();
var folderID =theFolder.getId();
var folder = DriveApp.getFolderById(folderID);
var zipped = Utilities.zip(getBlobs(folder, ''), folder.getName()+'.zip');
folder.getParents().next().createFile(zipped);

function getBlobs(rootFolder, path) {
  var blobs = [];
  var files = rootFolder.getFiles();
  while (files.hasNext()) {
    var file = files.next().getBlob();
    file.setName(path+file.getName());
    blobs.push(file);
  }
  var folders = rootFolder.getFolders();
  while (folders.hasNext()) {
    var folder = folders.next();
    var fPath = path+folder.getName()+'/';
    blobs.push(Utilities.newBlob([]).setName(fPath)); //comment/uncomment this line to skip/include empty folders
    blobs = blobs.concat(getBlobs(folder, fPath));
  }
  return blobs;
}

The only weird thing that I'm experiencing is that when I run the script it says TypeError: Cannot call method "getFiles" of undefined. (line 10, file "Code"). When I happened to look at the place where this script lives there was also 5 zip files that were complete. It works but I still get that error. Weird...but this code works for me. Thanks to everyone on this thread. Cheers!

1
votes

There's no API reference indeed. You could open an issue request regarding this on Apps Script issue tracker. But deducing from what the code-completion shows, here is my understanding:

var folder = DocsList.getFolder('path/to/folder');
var files = folder.getFiles();
var blobs = [];
for( var i in files )
  blobs.push(files[i].getBlob());
var zip = Utilities.zip(blobs, 'newFiles.zip');
folder.createFile(zip);

But I have not tested this code, so I don't know if it will work. Also, it may work only for files not converted to Google's format, or maybe only for those or a subset of it. Well, if you try it out and find something, please share here with us. One limit that you'll sure face is the filesize, it will probably not work if the zip file gets "too" big... yeah, you'll have to test this limit too.

0
votes

If Hafez solution didn't worked out, and you get this error

TypeError: Cannot read property 'getFiles' of undefined

Try doing this

/**
 * Creates a zipFile of the mentioned document ID and store it in Drive. You can search the zip by folderName.zip
 */

function createAndSendDocument() {
    var files = DriveApp.getFolderById("DOCUMENT ID CAN BE FIND IN THE URL WHEN A DOCUMENT IS OPENED");
    var folder = files;
    var zipped = Utilities.zip(getBlobs(folder, ''), folder.getName() + '.zip');
    folder.getParents().next().createFile(zipped);

}

function getBlobs(rootFolder, path) {
    var blobs = [];
    var files = rootFolder.getFiles();

    while (files.hasNext()) {
        var file = files.next().getBlob();
        file.setName(path+file.getName());
        blobs.push(file);
    }

    var folders = rootFolder.getFolders();

    while (folders.hasNext()) {
        var folder = folders.next();
        var fPath = path+folder.getName() + '/';
        blobs.push(Utilities.newBlob([]).setName(fPath)); //comment/uncomment this line to skip/include empty folders
        blobs = blobs.concat(getBlobs(folder, fPath));
    }

    return blobs;
}