Cannot find method (class)addFile - google-apps-script

I have way to much code to paste in, so I created the simplest version of my problem.
I get the error "Cannot find method (class)addFile($Proxy1084). (line 96, file "Macros")"
For the record, line 96 is the folder.addFile(copySS). It creates the sheet. Logger data will give me the name of the folder. If anyone has any clue why this isn't rolling I could use the assist.
function test2(){
var folders = DriveApp.getFolders();
var file = "Testy McFile";
while(folders.hasNext()){
var folder = folders.next();
// find all the NFL folders
if(folder.getName() === 'NFL'){
var copySS = SpreadsheetApp.create(file);
Logger.log(folder.getName());
folder.addFile(copySS);
//this is test code so in case it works... don't make a dozen copies
break;
}
}
}

copySS here is an Spreadsheet object, not file Object. However addFile method expects a file object from Drive app. That is why you are getting this error.
Here is modified code which works fine.
function test2(){
var folders = DriveApp.getFolders();
var file = "Testy McFile";
while(folders.hasNext()){
var folder = folders.next();
// find all the NFL folders
if(folder.getName() === 'Imp'){
var fileId = SpreadsheetApp.create(file).getId();
var file = DriveApp.getFileById(fileId);
Logger.log(folder.getName());
folder.addFile(file);
break;
}
}
}

Related

Moving files in Google drive results in getFilesByName is not a function error

I have a file by a specific name which it is not taking. Can you suggest?
I want it to be a named file in the drive which should be moved to the folder.
My Code :
function MoveFiles(){
var files = DriveApp.getFilesByName("Sampling Report-selected");
while (files.hasNext()) {
var file = files.next();
var destination = DriveApp.getFolderById("1-dh-xfZZdfnMOlPasy_yoJBnnAsFsRIZ");
destination.addFile(file);
var pull = DriveApp.getRootFolder();
pull.removeFile(file);
}
}
Error: TypeError: DriveApp.getRootFolder(...).getFiles(...).getFilesByName is not a function
Please tell me to set up the trigger every time a new file is created. Because I only want it to be uploaded only when a new file is created.

How can I modify this to save a spreadsheet into a new folder

I've found scripts that save a copy of a spread sheet, but so far I've not been able to figure out how to modify the following code to save my spreadsheet into the newly created/already existing folder.
//Create folder if it does not exist
function createFolder(folderID, folderName){
var parentFolder = DriveApp.getFolderById(folderID);
var subFolders = parentFolder.getFolders();
var doesntExist = true;
var newFolder = '';
// Check if folder already exists.
while(subFolders.hasNext()){
var folder = subFolders.next();
//If the folder exists return the id of the folder
if(folder.getName() === folderName){
doesntExist = false;
newFolder = folder;
return newFolder.getId();
};
};
//If the folder doesn't exist, then create a new folder
if(doesntExist == true){
//If the file doesn't exist
newFolder = parentFolder.createFolder(folderName);
return newFolder.getId();
};
};
function start(){
var FOLDER_ID = 'my folder id';
var NEW_FOLDER_NAME = SpreadsheetApp.getActiveSheet().getRange('A1').getValue();
var myFolderID = createFolder(FOLDER_ID, NEW_FOLDER_NAME);
};
Update:
My goal is to create a new folder based on the contents of cell A1 if that folder doesn't exist and save the file in that folder. If the folder already exists, then save the file in the existing folder. The file name will be in cell A2.
I want to save a copy, and leave the original file where it is.
Since September 30, 2020, Drive files cannot have multiple parent folders.
Therefore, you should either move your file to the new folder, or make a copy of the file. But you cannot have the same file in two different folders.
You should use either moveTo(destination), if you want to move the file to the new folder, or makeCopy(destination) if you want to copy your file to the new folder.
Update: You mentioned in comments that you want to make a copy the file (not move it) and specify the name of the copied file (corresponding to value in A2). Therefore, you should use makeCopy(name, destination).
Considering that you want to save the active spreadsheet, your main function could be like this:
function start(){
var PARENT_FOLDER_ID = 'my folder id';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var NEW_FOLDER_NAME = sheet.getRange('A1').getValue();
var FILE_NAME = sheet.getRange('A2').getValue();
var spreadsheetId = ss.getId();
var file = DriveApp.getFileById(spreadsheetId);
var folder = createFolder(PARENT_FOLDER_ID, NEW_FOLDER_NAME);
file.makeCopy(FILE_NAME, folder);
}
And the function createFolder could be greatly reduced in size, using Folder.getFoldersByName(name):
function createFolder(folderID, folderName){
var parentFolder = DriveApp.getFolderById(folderID);
var subFolders = parentFolder.getFoldersByName(folderName);
if (subFolders.hasNext()) return subFolders.next(); // Return existing folder
else return parentFolder.createFolder(folderName); // Return created folder
}
Notes:
Because of this behaviour change in Drive, methods like addFile(child) are deprecated.
Reference:
Single-parenting behavior changes
The script in your example creates a new folder. It doesn't save anything, as far as I can tell.
If you want just save your current spreadsheet in some already existing folder, here you go:
var id = SpreadsheetApp.getActiveSpreadsheet().getId();
var file = DriveApp.getFileById(id);
var folder = DriveApp.getFolderById("FOLDER_ID"); // <-- ID of the destination folder
folder.addFile(file);
Update. In case you know the name of destination folder and the folder shares the same parent folder with current spreadsheet file the script can look like this:
var ss = SpreadsheetApp.getActiveSheet();
var dest_folder_name = ss.getRange('A1').getValue();
var copy_name = ss.getRange('A2').getValue();
var dest_folder = "";
var file_id = SpreadsheetApp.getActiveSpreadsheet().getId();
var file = DriveApp.getFileById(file_id);
var parent_folder = file.getParents().next();
var sub_folders = parent_folder.getFolders();
// search a destination folder in current folder
while (sub_folders.hasNext()) {
dest_folder = sub_folders.next();
if (dest_folder.getName() === dest_folder_name) {
break;
}
dest_folder = "";
}
// create the destination folder if nothing was found
if (dest_folder === "") {
dest_folder = parent_folder.createFolder(dest_folder_name);
}
// copy the spreadsheet to the destination folder
file.makeCopy(copy_name, dest_folder);
The script tires to finds destination folder (the name taken from cell 'A1') inside current folder and creates the folder if nothing was found. After that it saves a copy of current spreadsheet (the name taken from cell 'A2').
NB. GoogleDrive allows files or subfolders with the same names inside one folder. So it's not unlikely to get many spreadsheets with identical names. Perhaps it makes sense to check names of existing files before the saving.

Google Script - Multi File Upload - How to Upload Files to New Sub-folder

I am trying to modify the below to code so the all files in the var fileBlob = e.parameter['file'+i]; are uploaded into the new sub-folder that is created.
After submitting the upload, a new folder is created for each file uploaded and each file is uploaded to each folder.
How can I get the doPost to submit the upload files to the new sub-folder only. So if I upload 20 files, 20 files are added/uploaded to the one sub-folder only.
Multi File Upload Ui Form
Google Drive Results
Code
function doPost(e) {
var foldername = e.parameter.folderName;
Logger.log('foldername = '+foldername);
var numFiles = Number(e.parameter.hidden);
Logger.log('numFiles = '+numFiles);
for (var i = 1; i<=numFiles; i++){
Logger.log(i);
var fileBlob = e.parameter['file'+i];
Logger.log(fileBlob);
var newFolder = DocsList.getFolderById("0Bw8NytPhOo00b0xIVm41LWlZRlk").createFolder(foldername);
newFolder.getUrl();
Logger.log(newFolder.getUrl());
var newFile = DocsList.createFile(fileBlob);
newFile.addToFolder(newFolder);
}
Full Code here (Created by Serge insas)
As mentioned in the other answer, the folder creation should happen just once before the loop but instead of adding the new file to the folder (and keeping it in the root folder as well unless you remove it) I would suggest to use the createFile method from the folder class instead.
The code becomes simpler :
function doPost(e) {
var foldername = e.parameter.folderName;
Logger.log('foldername = '+foldername);
var numFiles = Number(e.parameter.hidden);
Logger.log('numFiles = '+numFiles);
var newFolder = DocsList.getFolderById("0Bw8NytPhOo00b0xIVm41LWlZRlk").createFolder(foldername);
for (var i = 1; i<=numFiles; i++){
Logger.log(i);
var fileBlob = e.parameter['file'+i];
var newFile = newFolder.createFile(fileBlob);// create the file directly in the new folder
}
}
I think your problem here is that you call .createFolder for each file. Try putting
var newFolder = DocsList.getFolderById("0Bw8NytPhOo00b0xIVm41LWlZRlk").createFolder(foldername);
outside of the for loop.

Google apps script rename file not working

When running this script I get the error
TypeError: Cannot find function setName in object File. (line 8, file "Code")
function rename() {
var folder = DocsList.getFolder('Folder');
var files = folder.getFiles();
for (var i in files) {
oldName = files[i].getName()
newName = oldName.replace(/\d+/g, '')
newName = newName.replace(/\s/g, '');
files[i].setName(newName)
}
For me worked with setName().
files[i].setName(newName);
function myFunction()
{ **// this worked for me rename files of type CSV to processed**
var sh = SpreadsheetApp.getActiveSheet();
var folder = DriveApp.getFolderById('folderID'); // change accordingly to folder ID
//give me only files that are of type CSV
var files = folder.getFilesByType(MimeType.CSV);
// new name of csv that I want to rename the file within my google drive folder
var newName = "processed";
while(files.hasNext())
{
// iterate throught the csv files available
var file = files.next()
// will rename all csv's to processed
file.setName(newName);
}
}
The method is rename() and not setName()
files[i].rename(newName)

Creating a zip file inside Google Drive with Apps Script

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.
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'));
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;
}
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!
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.
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;
}