JavaScript, HTML, CSS e... !
24 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

24 Commenti

  1. Friday, February 9, 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
    • Friday, February 9, 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
      • Saturday, February 10, 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à

      • Saturday, February 10, 2018 alle ore 21:12 Michele PisaniAutore

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

  2. Sunday, May 13, 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
    • Sunday, May 13, 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. Wednesday, September 5, 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
    • Wednesday, September 5, 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
  4. Thursday, October 27, 2022 alle ore 12:08 Marco

    Ciao.
    Devo farti una domanda da inesperto totale.
    Se inserisco il codice tale e quale al tuo, mi restituisce l'errore: "Errore
    Exception: Invalid argument: id
    getCurrentProjectFolder @ Codice.gs:10
    startFunction @ Codice.gs:41"

    Devo inserire manualmente l'ID della cartella di origine e quello di quella di destinazione per caso?

    Ti ringrazio in anticipo per le spiegazione che potrai darmi.
    Marco

    Rispondi a questo commento
    • Thursday, October 27, 2022 alle ore 17:24 Michele PisaniAutore

      Ciao Marco,
      quelle info le prende in automatico. Quale funzione hai eseguito dall'editor di script?
      Sono da cell in questo momento, dove è l'argomento id che non lo vedo nel codice?

      Rispondi a questo commento
  5. Thursday, November 3, 2022 alle ore 12:38 MARCO

    Ciao e scusami il ritardo....
    La risposta completa dello script "startFunction" è:

    12:33:17 Notifica Esecuzione avviata
    12:33:18 Errore Exception: Invalid argument: id
    getCurrentProjectFolder @ Codice.gs:10
    startFunction @ Codice.gs:41


    Spero si veda bene.
    Grazie per la tua pazienza

    Rispondi a questo commento
    • Thursday, November 3, 2022 alle ore 12:41 Marco

      riga 10

      var thisFolder = DriveApp.getFolderById(thisFolderId);


      riga 41

      var cartellaProgettoCorrente = getCurrentProjectFolder();

      Rispondi a questo commento
      • Thursday, November 3, 2022 alle ore 14:55 Michele PisaniAutore

        Ciao Marco,
        il progetto di script di trova nella root o in una cartella dedicata?

  6. Thursday, November 3, 2022 alle ore 17:00 Marco

    dedicata

    Rispondi a questo commento
    • Saturday, November 5, 2022 alle ore 21:36 Michele PisaniAutore

      Ciao Marco,
      ho riprovato personalmente il codice a distanza di anni e ti confermo che funziona correttamente.
      Se lato tuo il codice è stato copiato correttamente e hai tutti gli accessi e privilegi ai file del tuo account, proverei semplicemente a creare un nuovo file di script eliminando quello su cui stai lavorando.

      Rispondi a questo commento
      • Monday, November 7, 2022 alle ore 18:11 marco

        Ok. Allora credo di non aver capito dove posizionare il modulko dove far lavorare il tuo script...
        Io ho creato una cartella con dei file e il modulo dove applicare il tuo script e un'altra cartella , 2, dove vorrei spostare i file della cartella 1. Cosa sbaglio?

      • Monday, November 7, 2022 alle ore 18:30 Michele PisaniAutore

        Questo script crea un nuovo file vuoto (nel caso specifico un Google Sheets) all'interno della stessa cartella dove si trova il progetto di script. Per fare quello che desideri il codice deve essere modificato, giocando con i metodi presentati.

  7. Tuesday, November 8, 2022 alle ore 12:43 marco

    Credo di aver capito il mio errore.... dove devo inserire l'ID della cartella di destinazione?

    Rispondi a questo commento
    • Tuesday, November 8, 2022 alle ore 13:09 Michele PisaniAutore

      Ciao Marco,
      non ho capito la domanda. Questo script effettua esattamente l'azione indicata perché lo script è al solo scopo esemplificativo dei metodi: crea un nuovo file Google Sheets vuoto nella cartella dove si trova il progetto che contiene la funzione. Così com'è, non è fatto per spostare specifici file in specifiche cartelle. Per ottenere il risultato desiderato i metodi da utilizzare sono sicuramente quelli presentati, ma non basta inserire gli id. Per qualsiasi altra personalizzazione è necessario capire bene cosa fanno i metodi e creare una nuova funzione ad hoc.

      Rispondi a questo commento
  8. Wednesday, November 9, 2022 alle ore 11:28 Marco

    Ciao e grazie ancora per la tua pazienza.
    L'equivoco credo che nasca dalla mia esigenza: io cercavo uno script che mi spostasse, massivamente, tutti i file di una certa cartella in un'altra da me scelta. E' possibile?

    Rispondi a questo commento
    • Wednesday, November 9, 2022 alle ore 11:47 Michele PisaniAutore

      Ciao Marco,
      ti confermo che è fattibilissimo utilizzando a dovere i metodi presentati nell'articolo. Quantomeno questo scambio di messaggi ha confermato che lo script dell'articolo funziona correttamente, il resto ora è puro divertimento per te. Sono certo che con un po' di prove e consapevolezza riuscirai in breve tempo a ottenere il risultato desiderato :)

      Rispondi a questo commento
  9. Thursday, February 2, 2023 alle ore 14:45 carmelo

    Buongiorno Michele ti scrivo per sapere se sia possibile fare questa cosa con app script dato che non ne ho idea.
    Ho un database di utenti di cui ho raccolto le iscrizioni tramite il nostro sito web ed attualmente, le foto che hanno caricato gli stessi, sono in una cartella del nostro sito.
    Vorremmo spostare tutto l'archivio su drive, ma il problema è ottenere il percorso assoluto di ognuno di questi file ( sono oltre 50mila e manualmente è impraticaabile farlo). Vengo al punto: con l'aiuto di un amico abbiamo creato uno script che partendo dal database utenti presente in sheets e che contiene i link originali al nostro sito, scarica i file in una cartella di drive rinominandoli con nome e cognome.
    Ora però il nostro problema è riassociare al database il nuovo link che è su drive. Credi che sia possibile automatizzare il processo, facendo fare una ricerca a DriveApp e ricostruire il link al contrario? cioè cercando cognome e nome dentro la cartella di drive, e farci rendere i relativi link in una colonna di un foglio google?

    spero di essermi spiegato :)

    grazie

    Rispondi a questo commento
  10. Thursday, February 2, 2023 alle ore 14:45 carmelo

    Buongiorno Michele ti scrivo per sapere se sia possibile fare questa cosa con app script dato che non ne ho idea.
    Ho un database di utenti di cui ho raccolto le iscrizioni tramite il nostro sito web ed attualmente, le foto che hanno caricato gli stessi, sono in una cartella del nostro sito.
    Vorremmo spostare tutto l'archivio su drive, ma il problema è ottenere il percorso assoluto di ognuno di questi file ( sono oltre 50mila e manualmente è impraticaabile farlo). Vengo al punto: con l'aiuto di un amico abbiamo creato uno script che partendo dal database utenti presente in sheets e che contiene i link originali al nostro sito, scarica i file in una cartella di drive rinominandoli con nome e cognome.
    Ora però il nostro problema è riassociare al database il nuovo link che è su drive. Credi che sia possibile automatizzare il processo, facendo fare una ricerca a DriveApp e ricostruire il link al contrario? cioè cercando cognome e nome dentro la cartella di drive, e farci rendere i relativi link in una colonna di un foglio google?

    spero di essermi spiegato :)

    grazie

    Rispondi a questo commento
  11. Thursday, February 2, 2023 alle ore 14:46 carmelo

    Buongiorno Michele ti scrivo per sapere se sia possibile fare questa cosa con app script dato che non ne ho idea.
    Ho un database di utenti di cui ho raccolto le iscrizioni tramite il nostro sito web ed attualmente, le foto che hanno caricato gli stessi, sono in una cartella del nostro sito.
    Vorremmo spostare tutto l'archivio su drive, ma il problema è ottenere il percorso assoluto di ognuno di questi file ( sono oltre 50mila e manualmente è impraticaabile farlo). Vengo al punto: con l'aiuto di un amico abbiamo creato uno script che partendo dal database utenti presente in sheets e che contiene i link originali al nostro sito, scarica i file in una cartella di drive rinominandoli con nome e cognome.
    Ora però il nostro problema è riassociare al database il nuovo link che è su drive. Credi che sia possibile automatizzare il processo, facendo fare una ricerca a DriveApp e ricostruire il link al contrario? cioè cercando cognome e nome dentro la cartella di drive, e farci rendere i relativi link in una colonna di un foglio google?

    spero di essermi spiegato :)

    grazie

    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]https://www.appsscript.it[/url] se devi riferirti ad un indirizzo web