Reputation: 21
I want to copy folders into a Master Folder within Google Drive. My main issue is creating a function when one column is not blank and another column is blank. Once, a new folder is created it has to paste in the folder URL in one of the columns.
This is what I have so far:
function addData(){
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data");
var lr = activeSheet.getLastRow();
var lc = activeSheet.getLastColumn();
var sourceData = sourceSheet.getRange(1, 1, lr, lc).getValues();
for (row in sourceData) {
if (sourceData[row][0] !== "" && sourceData[row][19] !== "") {
var rowNum = parseInt(row);
//code will go here for Folder copying and renaming and getting the new folder url
activeSheet.getRange(rowNum+1,lc).setValue("Completed"); //we will eventually change Completed with the new Folder URL
}
}
}
Upvotes: 2
Views: 4072
Reputation: 135
This solution is a variation that checks to see if the file or folder has already been copied.
Useful if you have to restart the execution.
It uses includes
to check if a file/folder has been copied:
It goes only one level deep, so won't copy subfolders of subfolders.
I've added a sort using Intl.Collator
because it helps me read the console output. Neither sort
nor console
are needed but may be useful.
references:
/** Use with copyFolderContents */
function copyFolder() {
const topFolderFrom = DriveApp.getFolderById(''); // enter folder ID
const topFolderTo = DriveApp.getFolderById(''); // enter folder ID
// Get the subfolder names and IDs
const ffTopFolder = topFolderFrom.getFolders();
const subfolders = [];
while (ffTopFolder.hasNext()) {
let folder = ffTopFolder.next();
let ffnameid = [];
ffnameid.push(folder.getName(), folder.getId());
subfolders.push(ffnameid);
}
subfolders.sort((a, b) => collator.compare(a[0], b[0]));
// Get target subfolder names
const folderstarget = topFolderTo.getFolders();
const listtarget = [];
while (folderstarget.hasNext()) {
let foldertarget = folderstarget.next();
let ffname = [];
ffname.push(foldertarget.getName());
listtarget.push(ffname);
}
listtarget.sort(collator.compare);
// Check if subfolder has already been created
const alreadycreated = listtarget.flat();
const stilltocreate = subfolders.filter(e => !alreadycreated.includes(e[0]));
console.log('subfolders already created:\n', alreadycreated);
console.log('subfolders still to create:\n', stilltocreate.map(e => e[0]));
// Create subfolders
for (let i = 0, len = stilltocreate.length; i < len; i++) {
topFolderTo.createFolder(stilltocreate[i][0]);
}
// Get the name and ID of subfolders in target folder (needed in case subfolders have been created)
const ffTopFolderTo = topFolderTo.getFolders();
const subfoldersTo = [];
// Get the subfolders
while (ffTopFolderTo.hasNext()) {
let folder = ffTopFolderTo.next();
let ffnameid = [];
ffnameid.push(folder.getName(), folder.getId());
subfoldersTo.push(ffnameid);
}
subfoldersTo.sort((a, b) => collator.compare(a[0], b[0]));
// Add the top level folders to arrays to copy files in top level
subfolders.push([topFolderFrom.getName(), topFolderFrom.getId()]);
subfoldersTo.push([topFolderTo.getName(), topFolderTo.getId()]);
console.log('subfolders and top folder:\n', subfolders);
console.log('subfolders and top folder (target):\n', subfoldersTo);
for (let i = 0, len = subfolders.length; i < len; i++) {
let copyFrom = DriveApp.getFolderById(subfolders[i][1]);
let indx = subfoldersTo.map(e => e[0]).indexOf(subfolders[i][0]);
let copyTo = DriveApp.getFolderById(subfoldersTo[indx][1]);
// Call the function that copies the folder
copyFolderContents_(copyFrom, copyTo);
}
}
/** Copies all the files in a folder to another one, checking for duplicates */
function copyFolderContents_(source, target) {
Logger.log('copy from: ' + source);
Logger.log('copy to: ' + target);
// Get source filenames and IDs
const files = source.getFiles();
const listsource = [];
while (files.hasNext()) {
let file = files.next();
let ssnameid = [];
ssnameid.push(file.getName(), file.getId());
listsource.push(ssnameid);
}
listsource.sort((a, b) => collator.compare(a[0], b[0]));
// Get target filenames
const filestarget = target.getFiles();
const listtarget = [];
while (filestarget.hasNext()) {
let filetarget = filestarget.next();
let ssname = [];
ssname.push(filetarget.getName());
listtarget.push(ssname);
}
listtarget.sort(collator.compare);
// Check if file has already been copied
const alreadycopied = listtarget.flat();
const stilltocopy = listsource.filter(e => !alreadycopied.includes(e[0]));
console.log('files already copied:\n', alreadycopied);
console.log('files still to copy:\n', stilltocopy.map(e => e[0]));
// Copy files still to copy
for (let i = 0, len = stilltocopy.length; i < len; i++) {
let fileid = stilltocopy[i][1];
let ss = DriveApp.getFileById(fileid);
Logger.log(i + ' - ' + ss);
ss.makeCopy(stilltocopy[i][0], target);
}
}
/** Used for sorting alpha/numeric arrays */
const collator = new Intl.Collator('en', {
numeric: true,
sensitivity: 'base'
})
Upvotes: 0
Reputation: 2861
The main idea would be to iterate files using Folder.getFiles()
and folders with Folder.getFolders()
. Make new folders with Folder.createFolder(name)
and copy files using File.makeCopy(name, destination)
:
/**
* Copies all the files in a folder to another one.
*/
function copyFolderContents_(source, target) {
// Iterate files in source folder
const filesIterator = source.getFiles()
while (filesIterator.hasNext()) {
const file = filesIterator.next()
// Make a copy of the file keeping the same name
file.makeCopy(file.getName(), target)
}
}
/**
* Recursivelly copies a folder and all its subfolders with all the files
*/
function copyFolder_(toCopy, copyInto) {
// Makes the new folder (with the same name) into the `copyInto`
const newFolder = copyInto.createFolder(toCopy.getName())
// Copy the contents
copyFolderContents_(toCopy, newFolder)
// Iterate any subfolder
const foldersIterator = toCopy.getFolders()
while (foldersIterator.hasNext()) {
const folder = foldersIterator.next()
// Copy the folder and it's contents (recursive call)
copyFolder_(folder, newFolder)
}
}
/**
* Entry point to execute with the Google Apps Script UI
*/
function copyFolder() {
// Get the folders (by ID in this case)
const toCopy = DriveApp.getFolderById('')
const copyInto = DriveApp.getFolderById('')
// Call the function that copies the folder
copyFolder_(toCopy, copyInto)
}
You need to add the ids of the folder to be copied and the folder to copy it from on copyFolder()
.
foldersIterator
and filesIterator
are Google Apps Script Iterators. They have a method hasNext()
that returns if there is another item, and a next()
that retrieves it.
Note that copyFolder_(toCopy, copyInto)
uses itself to copy its subfolders.
Upvotes: 9