Javascript, HTML, CSS e... !
8 commenti

Puoi usare due metodi: addFile o makeCopy

Spostare i file tra le cartelle di Google Drive con Google Apps Script

Le classi relative ai file ed alle cartelle, in Google Apps Script, non mettono a disposizione alcun metodo per spostare un file da una cartella ad un'altra in Google Drive, tuttavia è possibile aggiungere lo stesso file in più cartelle. Sfruttando questa caratteristica possiamo ovviare alla mancanza di un metodo dedicato per spostare direttamente un file semplicemente aggiungendolo ad una cartella desiderata ed eliminandolo da quella di origine.

L'esempio di codice che andrò a presentare vuole simulare una classica situazione in cui uno sviluppatore in Apps Script si trova quando è alle prese con la generazione di nuovi file; non riporterò pertanto una isolata porzione di codice bensì una serie di funzioni completa che partono dal recupero della cartella corrente, procedono con la creazione di un nuovo file e terminano con il suo 'spostamento' nella cartella in cui è presente il progetto in corso (ho apostrofato il termine 'spostamento' in virtù del fatto che, nonostante il risultato finale, non si tratta tecnicamente di un vero e proprio spostamento tra cartelle).

Il codice completo del flusso indicato sopra è il seguente:

function getCurrentProjectFolder() {
  var thisScriptId = ScriptApp.getScriptId();
  var thisFile = DriveApp.getFileById(thisScriptId);
  var parentFolders = thisFile.getParents();
  var thisFolderId;
  while (parentFolders.hasNext()){
    thisFolderId = parentFolders.next().getId();
  }
  // Recupera l'istanza della cartella
  var thisFolder = DriveApp.getFolderById(thisFolderId);
  return thisFolder;
}

function createNewFile(fileType, fileName) {
  var nuovoFile;
  switch (fileType) {
    case 'spreadsheet':
      nuovoFile = SpreadsheetApp.create(fileName);
      break;
    case 'document':
      nuovoFile = DocumentApp.create(fileName);
      break;
    case 'form':
      nuovoFile = FormApp.create(fileName);
      break;
    default:
      nuovoFile = SpreadsheetApp.create('nuovo file');
  }
  return nuovoFile;
}

function moveFileToFolder(nuovoFile, targetFolder) {
  var nuovoFileId = DriveApp.getFileById(nuovoFile.getId());  
  var parentFolder = nuovoFileId.getParents();
  var movedFile = targetFolder.addFile(nuovoFileId);
  parentFolder.next().removeFile(nuovoFileId);
  return movedFile;
}

function startFunction() {
  var cartellaProgettoCorrente = getCurrentProjectFolder();
  var nuovoFile = createNewFile('spreadsheet', 'file da spostare nella cartella del progetto');
  var movedFile = moveFileToFolder(nuovoFile, cartellaProgettoCorrente);
}

Ho chiamato, per facilità di identificazione, la funzione di inizio con il nome di startFunction(), al suo interno ci sono 3 chiamate a 3 distinte funzioni (riutilizzabili in altri script e contesti), la prima è getCurrentProjectFolder() che si occupa proprio di recuperare il riferimento della cartella (tramite il suo id) nella quale si trova il progetto corrente:

function getCurrentProjectFolder() {
  // Recupera l'id dello script corrente
  var thisScriptId = ScriptApp.getScriptId();
  // Recupera l'istanza del file thisScriptId
  var thisFile = DriveApp.getFileById(thisScriptId);
  // Recupera il riferimento degli elementi del livello superiore al file
  var parentFolders = thisFile.getParents();
  var thisFolderId;
  while (parentFolders.hasNext()){
    // Recupera l'id della cartella del file
    thisFolderId = parentFolders.next().getId();
  }
  // Recupera l'istanza della cartella
  var thisFolder = DriveApp.getFolderById(thisFolderId);
  return thisFolder;
}

La seconda funzione chiamata è createNewFile(fileType, fileName) che accetta in ingresso due parametri (il tipo di file identificato da una stringa: 'spreadsheet', 'document' o 'form'; il nome del documento, anch'esso ovviamente una stringa), questa funzione crea il file (del tipo e con il nome indicati) nella root di Google Drive e ne restituisce il riferimento:

function createNewFile(fileType, fileName) {
  // crea un nuovo documento nella root di Drive
  var nuovoFile;
  switch (fileType) {
    case 'spreadsheet':
      nuovoFile = SpreadsheetApp.create(fileName);
      break;
    case 'document':
      nuovoFile = DocumentApp.create(fileName);
      break;
    case 'form':
      nuovoFile = FormApp.create(fileName);
      break;
    default:
      nuovoFile = SpreadsheetApp.create('nuovo file');
  }
  return nuovoFile;
}

La terza funzione, chiamata moveFileToFolder(nuovoFile, targetFolder), accetta in ingresso due parametri ovvero, il riferimento al file appena creato e quello alla cartella di destinazione recuperata tramite la prima funzione. Questa funzione è il cuore dello 'spostamento' dei file tra cartelle in quanto tramite l'id del file recupera il riferimento degli elementi del suo livello superiore che, come abbiamo definito poco fa, è la root di Google Drive, dopodiché tramite il metodo addFile aggiunge il file alla cartella desiderata (quella passata nei parametri) e successivamente removeFile rimuove l'istanza dello stesso file dalla root di Drive:

function moveFileToFolder(nuovoFile, targetFolder) {
  // recupera l'id del nuovo file
  var nuovoFileId = DriveApp.getFileById(nuovoFile.getId());  
  // Recupera il riferimento degli elementi del livello superiore al file (la root di Drive)
  var parentFolder = nuovoFileId.getParents();
  // Aggiunge l'istanza del file all'interno della cartella desiderata
  var movedFile = targetFolder.addFile(nuovoFileId);
  // Rimuove il file (la sua istanza) dalla root
  parentFolder.next().removeFile(nuovoFileId);
  return movedFile;
}

Con questo metodo lo 'spostamento' dei file è quasi indolore, dico quasi perchè all'evidenza l'operazione è del tutto trasparente, non si troverà alcun file nel cestino ed il path di accesso al file spostato è lo stesso di quello originariamente presente nella root, tuttavia il suo id (qualora servisse utilizzarlo come riferimento per particolari operazioni a runtime dalla creazione allo 'spostamento') sarà diverso dal file di partenza.

Un altro metodo che potrebbe essere utilizzato sempre allo scopo di 'spostare' i file tra cartelle di Drive è makeCopy; personalmente non lo preferisco, quantomeno se lo scopo è quello oggetto di questo tutorial semplicemente perché effettuando l'operazione in questione (quindi copia del file nella cartella bersaglio ed eliminazione del file originale dalla root), troverei il file originale nel cestino (il metodo di cancellazione del file non a caso si chiama setTrashed) ma soprattutto il path di accesso al file spostato è diverso di quello originariamente presente nella root per il semplice motivo che è una copia del file (un nuovo file diverso dal precedente se pur identico nel nome e nel contenuto) e non un'istanza dello stesso (come si ottiene invece con il metodo precedentemente spiegato nel tutorial). Anche in questo caso, a maggior ragione, gli id tra i due file saranno diversi. Inoltre, questo metodo non andrà a buon fine se il file che si intende gestire è stato caricato da altro utente e lo script è in esecuzione sotto un utente diverso.

Per approfondimenti su tutti i metodi delle Classi per la gestione di file e cartelle rimando alla documentazione ufficiale della Classe DriveApp.

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

8 Commenti

  1. venerdì 9 febbraio 2018 alle ore 21.27 Mauro

    Salve script molto interesante una domanda e' possibile con il comando createFolder(name) creare una cartella nidificata ? creo una cartella "cartella2" che all'interno di "Cartella1" e poi li sposto i miei file
    grazie

    Rispondi a questo commento
    • venerdì 9 febbraio 2018 alle ore 22.09 Michele PisaniAutore

      Ciao Mauro,
      questa porzione di codice che ti riporto di seguito credo sia quello che stai cercando.
      In pratica, in base al nome indicato per la cartella padre verifica la sua presenza su Drive, se la trova ne prende il riferimento altrimenti crea una cartella con quel nome, successivamente in base al riferimento della cartella padre crea al suo interno una sottocartella e a sua volta, all'interno di questa sottocartella, crea un file:

      function createSubFolderAndFile() {
      var cartellaPadre_name = "Cartella padre";
      var cartellaPadre_iter = DriveApp.getFoldersByName(cartellaPadre_name);
      var cartellaPadre_ref = (cartellaPadre_iter.hasNext()) ? cartellaPadre_iter.next() : DriveApp.createFolder(cartellaPadre_name);
      var cartellaFiglia_ref = cartellaPadre_ref.createFolder('Cartella figlia');
      cartellaFiglia_ref.createFile('File HTML test', '<b>Ciao, da appsscript.it!</b>', MimeType.HTML);
      }



      Il codice dovrebbe essere abbastanza autoesplicativo, in ogni caso se c'è qualcosa che non ti torna fammi sapere.

      Rispondi a questo commento
      • sabato 10 febbraio 2018 alle ore 13.48 Mauro

        Intanto grazie infine per la risposta celere.... ho capito tutto non posso fare altro che ringraziarti e lodare la tua professionalità

      • sabato 10 febbraio 2018 alle ore 21.12 Michele PisaniAutore

        Grazie a te Mauro,
        è un piacere. Buon proseguimento!

  2. domenica 13 maggio 2018 alle ore 16.12 Mauro

    Ciao scusa il disturbo ma da un po questa funzione mi genera un errore hanno cambiato qualcosa sulle funzioni di Google ??
    var nuovoFileId = DriveApp.getFileById(nuovoFile.getId());
    mi segnala "impossibile chiamare metodo "getid" undefinid "
    fino a qualche tempo fa funzionava perfettamente

    Rispondi a questo commento
    • domenica 13 maggio 2018 alle ore 23.43 Michele PisaniAutore

      Ciao Mauro,
      probabilmente la tua variabile 'nuovoFile' non contiene effettivamente ciò che ti aspetti.
      Ho provato a lanciare questa funzione di test ed il risultato viene restituito nel log senza alcun problema:

      function getFileById() {
      var files = DriveApp.getFiles();
      while (files.hasNext()) {
      var file = files.next();
      Logger.log(DriveApp.getFileById(file.getId()));
      }
      }

      Rispondi a questo commento
  3. mercoledì 5 settembre 2018 alle ore 14.24 Domenico

    Buongiorno, stavo utilizzano il suggerimento (secondo me molto interessante) per potre creare un foglio nuovo con un nuovo nome su una cartella indicata.
    ma nella funzione

    function getCurrentProjectFolder() {
    var thisScriptId = ScriptApp.getScriptId();
    var thisFile = DriveApp.getFileById(thisScriptId);
    }


    recupera correttamente l'ID dello script ma poi mi da un errore nella riga in cui deve utilizzarlo ultima riga nell'esempio con il seguente errore
    Nessun elemento trovato con l'ID specificato o non disponi di autorizzazioni per accedervi.

    Sa mica quale potrebbe essere il motivo?

    Rispondi a questo commento
    • mercoledì 5 settembre 2018 alle ore 16.13 Michele PisaniAutore

      Ciao Domenico,
      l'errore in questione, che in base alle impostazioni di lingua può comparire in questo modo "No item with the given ID could be found, or you do not have permission to access it", viene restituito, come da descrizione, se nessun elemento in Drive è associato a quell'id o se non hai i permessi per accedervi. Nel tuo caso dato che parli di "Fogli" mi viene da pensare che la situazione sia la prima in quanto stai tentando di cercare su Drive il file con l'id dello script incorporato nello Spreadsheet, ma gli script incorporati non si 'trovano' su Drive.
      Prova a modificare il codice in modo da recuperare l'id dello Spreadsheet e riferirti a quello.

      Rispondi a questo commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]http://www.appsscript.it[/url] se devi riferirti ad un indirizzo web