0

I've been looking through the whole internet looking for a How to or a code to list my Shared Drive files. At the beggining I found one that seemed to work but after further testing it had major flaws with the way it scanned folders.

Now I've apparently found again some code that I had to adapt to use in order to make it work with Shared Drives but I managed to do it. My only issue is that it only seems to to list the files inside the first folder/subfolder it finds and doesn't loop. My issue is that it is too fast for me to diagnose and after a whole weekend of setup of my spreadsheet I don't have the time nor the knowledge to fix it myself.

Here is the code that I adapted to work with Shared Drives:

    function ListarTodo() {
  /* Adapted from Adapted Code written by @Andres Duarte and Adapted by @Eric Aya in this link:
    https://stackoverflow.com/a/63267959/18311037
  */

  // Lista todos los archivos de una carpeta y de sus sub carpetas, y toma el nombre de la carpeta a analizar del nombre de la hoja activa.
  // List all files and sub-folders in a single folder on Google Drive, and get the name of the activesheet to know the folder desired.
  var parentFolder = DriveApp.getFolderById("INSERT YOUR FOLDER ID HERE");

  // Declaramos la hoja // declare this sheet
  var sheet = SpreadsheetApp.getActive().getSheetByName('INSERT YOUR SHEET NAME HERE');
  // Borramos los datos de la hoja // clear any existing contents
  sheet.clear();
  // Agregamos una linea con los titulos // append a header row
  sheet.appendRow(["Carpeta","Nombre Archivo", "Fecha ultima modificacion", "Tamaño MB", "URL", "ID", "Descripción", "Tipo archivo"]);

  // getFoldersByName = obtener una coleccion de todas las carpetas en la unidad Drive que tienen el nombre buscado "foldername".
  // folders es un "iterador de carpetas" pero hay solo una carpeta para llamar por el nombre, por eso tiene un solo valor (next)
  // getFoldersByName = Gets a collection of all folders in the user's Drive that have the given name.
  // folders is a "Folder Iterator" but there is only one unique folder name called, so it has only one value (next)
  var folders = parentFolder.getFolders();
  var foldersnext = folders.next();
  var lintotal = 2;

  //Iniciamos la funcion recursiva // Initiate recursive function
  lintotal = SubCarpetas(foldersnext, parentFolder.getName(), lintotal);  
}

function SubCarpetas(folder, path, cantlineas) {
  cantlineas = ListarArchivos(folder, path, cantlineas);
  var subfolders = folder.getFolders();

  while (subfolders.hasNext()) {
    var mysubfolders = subfolders.next();
    var mysubfolderName = mysubfolders.getName(); 
    var newpath = "";
    newpath = path + "/" + mysubfolderName;
    cantlineas = SubCarpetas(mysubfolders, newpath, cantlineas);
  }
  return(cantlineas) 
}

function ListarArchivos(mifoldersnext, mipath, milintotal) {
  var datos = []; //array temporal que vamos a usar para grabar en la hoja
  var files = []; //array con todos los archivos que encontramos en la carpeta que estamos evaluando
  var file = []; //array que usamos para volcar los datos de cada archivo antes de guardarlo
  var total = 0;
  var sheet = SpreadsheetApp.getActiveSheet();
  var myfiles = mifoldersnext.getFiles();

// Creamos un array con los datos de cada archivo y guardamos el total de archivos
while (myfiles.hasNext()) {
    files.push(myfiles.next());
    total++;
}
//ordenamos el array por nombre de archivo alfabeticamente  //sorts the files array by file names alphabetically
files = files.sort(function(a, b){
   var aName = a.getName().toUpperCase();
   var bName = b.getName().toUpperCase();
   return aName.localeCompare(bName);
});

////
var vuelta = 0;
var bulk = 10; //Definimos la cantidad de lineas a grabar cada vez, en la hoja de la planilla GoogleDoc
var linea = milintotal; //definimos en que linea vamos a grabar en la planilla
for (var i = 0; i < files.length; i++) { //recorremos el array de archivos y formateamos la informacion que necesitamos para nuestra planilla
    file = files[i];
    var fname = file.getName(); //nombre del archivo
    var fdate = file.getLastUpdated(); //fecha y hora ultima modificacion
    var fsize = file.getSize(); //tamaño del archivo, lo pasamos de byte a Kbyte y luego a Mb
    fsize = +fsize.toFixed(2); //lo formateamos a dos decimales
    var furl = file.getUrl(); //url del archivo
    var fid = file.getId(); //id del archivo
    var fdesc = file.getDescription(); //descripcion
    var ftype = file.getMimeType(); //tipo de archivo
    datos[vuelta] = [mipath+" ("+total+")", fname, fdate, fsize, furl, fid, fdesc, ftype]; //ponemos todo dentro de un array temporal
    vuelta++;
    if (vuelta == bulk) {//cuando alcanza la cantidad definida, guarda este array con 10 lineas y lo vacía
      linea = milintotal;
//      Logger.log("linea = "+linea); //DEBUG
//      Logger.log("vuelta = "+vuelta); //DEBUG
//      Logger.log("total = "+total); //DEBUG
//      Logger.log("lintotal = "+milintotal); //DEBUG
//      Logger.log("registros en datos = "+datos.length); //DEBUG
//      Logger.log("data = "+datos); //DEBUG
      sheet.getRange(linea, 1, bulk,8).setValues(datos); //guardamos los datos del array temporal en la hoja
      SpreadsheetApp.flush(); //forzamos que aparezcan los datos en la hoja - sin esto los datos no aparecen hasta terminar (genera mucha impaciencia)
      milintotal = milintotal + vuelta;
      datos = []; //vaciamos el array temporal
      vuelta = 0;
      }
    }

if (datos.length>0) {//Al salir del bucle grabamos lo que haya quedado en el array datos
      linea = milintotal;
//      Logger.log("linea = "+linea); //DEBUG
//      Logger.log("vuelta = "+vuelta); //DEBUG
//      Logger.log("total = "+total); //DEBUG
//      Logger.log("lintotal = "+milintotal); //DEBUG
//      Logger.log("registros en datos = "+datos.length); //DEBUG
//      Logger.log("data = "+datos); //DEBUG
      sheet.getRange(linea, 1, datos.length,8).setValues(datos);
      SpreadsheetApp.flush(); //ansiolítico
      milintotal = milintotal + datos.length;
      datos = [];
      vuelta = 0;
    }
return (milintotal)
}

And here is the LINK to the original comment/code.

I'm new to StackOverflow so I'll do my best to mark the solutions and give feedback on the answers.

Tanaike
  • 181,128
  • 11
  • 97
  • 165
Alecs 1710
  • 13
  • 1
  • 2
  • In your situation, can I ask you about the reason that you don't use the script in your previous question? https://stackoverflow.com/q/71270142 – Tanaike Mar 01 '22 at 03:37
  • I had too many issues with it. It works but it's too slow and times out before it finishes listing the items. Another issue is that, after I managed to make it "work faster" I realized it was very difficult to actually keep a coherent track of my files – Alecs 1710 Mar 01 '22 at 06:19
  • Thank you for replying. In your question, you don't want to use the script in your previous question. [Ref](https://stackoverflow.com/q/71270142) And, do you want to use your showing script in your this question? For example, when there is a sample script with a low process cost, how about it? Because in your showing script, `setValues` is used in the loop. In this case, the cost becomes high. By the way, what values of file metadata do you want to retrieve? – Tanaike Mar 01 '22 at 07:15
  • I'll give better context of what I'm trying to do. I'm currently in charge of managing that at this time has 395 files that I need to list to then manually add their original link. Name, size, added date,modification date and url are needed. The amount of files will drastically increase to about 2000 in the next 2 weeks at most, so the code must be a lot faster. Also, It would be nice if it kept track every 5 min with an activator, so it cannot also have a "resume" option to bypass the 5 min execution limit. – Alecs 1710 Mar 01 '22 at 07:27
  • After a long time learning Apps Script this weekend I actually managed to make the previous code, which times out if you have more than 250 files, to list an amazing 395 files in 29 secs by changing appendRow to a push(data) with a variable that gets files in bulks. As it seems, this only works if it lists the files begging with the folders that don&#39;t have subfolders. I could've fixed what was wrong with that one, but since both are based on the same code and this one has everything I had to do with the data already implemented I decided to just try to make this one work. @Tanaike – Alecs 1710 Mar 01 '22 at 07:37
  • Thank you for replying. In your question, in order to reduce the process cost, can I propose a new sample script? – Tanaike Mar 01 '22 at 07:38
  • Of course, any code suggestion really helps. – Alecs 1710 Mar 01 '22 at 07:43
  • Thank you for replying. From your replying, I proposed a sample script as an answer. Could you please confirm it? If that was not useful, I apologize. – Tanaike Mar 01 '22 at 07:48

1 Answers1

0

From your comment, I believe your goal is as follows.

  • You want to retrieve the file and folder list from the specific folder.
  • You want to retrieve the metadata of "Name", "size", "added date", "modification date", "url".
  • You want to achieve this using Google Apps Script.
  • You want to reduce the process cost of the script for achieving this.

When I saw your showing script, setValues is used in the loop. In this case, the process cost becomes high. So, in this case, how about the following sample script?

In this sample script, a Google Apps Script library is used. Ref I created this library for retrieving the file and folder list with the low process cost using Google Apps Script.

Usage:

1. Install Google Apps Script library.

You can see the method for installing the library at here.

2. Enable Drive API.

This library uses Drive API. So please enable Drive API at Advanced Google services.

3. Sample script.

function sample() {
  const folderId = "###"; // Please set the top folder ID.

  // 1. Retrieve file and folder list under the specific folder.
  const { files } = FilesApp.createTree(folderId, null, "files(name,modifiedTime,createdTime,size,quotaBytesUsed,webViewLink,description)");

  // 2. Parse the list and create an array for putting to Spreadsheet.
  if (files.length == 0) return;
  const header = ["Name", "size", "added date", "modification date", "url", "description"];
  const values = [header, ...files.flatMap(({ filesInFolder }) => filesInFolder.map(e => [e.name, Number(e.quotaBytesUsed || e.size), new Date(e.createdTime), new Date(e.modifiedTime), e.webViewLink, e.description]))];

  // 3. Put the values to the Spreadsheet.
  const sheetName = "Sheet2"; // Please set the sheet nane.
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  sheet.clearContents();
  sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}
  • In this script, folderId can use both your Drive and the shared Drive.
  • When this script is run, the file and folder list is retrieved from folderId and put the values of "Name", "size", "added date", "modification date", "url" to the Spreadsheet.

Reference:

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • I a little embarrassed that last night, before going to bed, I looked through GitHub looking for anything to help me achieve what I needed and I actually found your repository without realizing it was yours. I marked it as favourite and had planned to test it when I get back home. Thank you so much, and I'm sorry for wasting your time – Alecs 1710 Mar 01 '22 at 07:52
  • @Alecs 1710 Thank you for replying. If this script is useful, I'm glad. I sometimes have the situation that file list are required to be retrieved from Google Drive. But, the process cost will be high when I created a sample script. So I had thought that when the script with the low cost for achieving this is existing, it might be useful for other users. So I created it. In the current stage, not only Google Apps Script, but also I have created for Go, Javascript, Node.js, python. [Ref](https://tanaikech.github.io/2020/06/01/updated-getfilelist-for-golang-javascript-node.js-and-python/) – Tanaike Mar 01 '22 at 07:59
  • It works amazingly, thank you so much, it is extreamly fast and seems to be accurate too. Just one last thing, I missed the fact that I also need the description. Any help with that? I went to the github repository but didn't really find any info to do it myself – Alecs 1710 Mar 01 '22 at 10:50
  • @Alecs 1710 I would like to support you. But, I have to apologize for my poor English skill. Unfortunately, about your new question of `Just one last thing, I missed the fact that I also need the description. Any help with that?`, I cannot understand it. Can I ask you about the detail of your new question? – Tanaike Mar 01 '22 at 11:34
  • My files have a description that I need to get listed too. In my other question the code is childFile.getDescription () for example – Alecs 1710 Mar 01 '22 at 11:38
  • @Alecs 1710 Thank you for replying. About your new question, I added the description to the last column. Could you please confirm it? – Tanaike Mar 01 '22 at 11:51
  • Yes, thank you. As a suggestion, you should list all these arguments in GitHub – Alecs 1710 Mar 01 '22 at 11:54
  • @Alecs 1710 Thank you for replying. About `Yes, thank you. As a suggestion, you should list all these arguments in GitHub`, I have to apologize for my poor English skill. I had already been mentioned it at `fields`. I deeply apologize for this again. – Tanaike Mar 01 '22 at 11:57