Google Drive：フォルダ丸ごとコピー：フォルダ階層下のすべてのファイル・フォルダを同じフォルダ構造のまま一度にコピーする

　次のURLでより使いやすくなった，フォルダ丸ごとコピー，を紹介しています。ご参照ください。
https://qiita.com/matsuhandy/items/00bce2397ba8e9ca58e1

#GoogleDriveのフォルダ丸ごとコピー
##できること
　GoogleDrive上で，次のようなフォルダ構造
![1.png](https://qiita-image-store.s3.amazonaws.com/0/146927/6121dc41-4754-aa63-f595-af3938e21131.png)
があったとして，「フォルダ1」を階層下をすべて含んで，
![2.png](https://qiita-image-store.s3.amazonaws.com/0/146927/3007353e-f4f4-cf9c-c4c7-d5a9ccd0adee.png)
のようにコピーします。図では各フォルダ配下にフォルダが1つしかありませんが，複数存在してもその通りにコピーします。
　GoogleDriveは同じフォルダ名・ファイル名が許容されているため，コピーしたフォルダのルートフォルダ名だけは自動で「（コピー）」を付けるか，事前にフォルダ名を指定しておきます。
　なお，「フォルダ1（コピー）」を作成する場所（フォルダ）は任意です。図のように「フォルダ0」の配下でも構いませんし，IDを事前に調べておくことで任意のフォルダを指定できます。
　Windowsだとエクスプローラでドラッグ一発ですが，GoogleDriveはファイルを一つずつコピーしては移動してファイル名を変更する･･･なんて繰り返さなければならないので，作ってみました。これでバックアップを取るのがとても楽になります。

##実現方法
###手順
　GoogleSpreadSheetにコピー元やコピー先を指定します。「ツール」「スクリプトエディタ」でコピープログラムを記述して実行します。
###GoogleSpreadSheetにコピー元フォルダ・コピー先フォルダを設定
　図のようにGoogleSpreadSheetにコピー元フォルダIDとコピー先フォルダIDを記述します。上の図のようにコピーするのであれば，コピー先フォルダは，「フォルダ0」のIDを指定します。なお，コピー元フォルダ名は書いてあっても無視されます。コピー元フォルダIDに実際に付いている名前が使われます。単なるメモです。
![3.png](https://qiita-image-store.s3.amazonaws.com/0/146927/69289b05-29ee-c9c6-9143-3284e9a84f95.png)
　コピー先フォルダ名に何か書いてあればそれをコピーされたフォルダのルートのフォルダ名になります。書いてなければ，コピー元フォルダIDのフォルダ名に「（コピー）」が付けられたものになります。
　なおSpreadSheetの名前は，図のように「フォルダコピー」等，わかりやすいものにしておきます。お気づきと思いますが，このSpreadSheet「フォルダコピー」は任意の場所に置けます。私はコピーするフォルダがあるフォルダ，上の図でいうと，「フォルダ0」の配下（「フォルダ1」と同列）に置いています。
　フォルダ丸ごとコピーをする際，このSpreadSheet「フォルダコピー」を移動するのは良いのですが，コピーする場合は「フォルダコピー」のIDが変わりますので，ソース中の「XXXXXXXXXXXXXXXXXXXXXXXXXX」の部分も変更します（次節参照）。（どなたか，自分自身のファイルIDを知る方法をご存じでしたら教えてください）

###GoogleSpreadSheetの「ツール」「スクリプトエディタ」でコピープログラムを記述
　SpreadSheet「フォルダコピー」の「ツール」「スクリプトエディタ」に次のプログラムを記述します。「XXXXXXXXXXXXXXXXXXXXXXXXXX」の部分は，SpreadSheet「フォルダコピー」のIDをURLからコピー・ペーストします。

![6.png](https://qiita-image-store.s3.amazonaws.com/0/146927/ef8cbbd6-a021-0af5-90bf-6fb9c1f2f4bf.png)

```javascript:フォルダコピー
function folderCopy() {
  
  var ss = new Ssheet("XXXXXXXXXXXXXXXXXXXXXXXXXX");//フォルダコピー，のspreadsheetのID

  var srcFolderId = ss.getValue(0, 2,2);//コピー元
  var srcFolder = DriveApp.getFolderById(srcFolderId);
  var srcFolderName = srcFolder.getName();

  var dstFolderId = ss.getValue(0, 3,2);//このフォルダー内に，フォルダーのコピーを作る
  var dstFolder = DriveApp.getFolderById(dstFolderId);
  var dstFolderName = ss.getValue(0, 3,3);
  if(dstFolderName=="") dstFolderName = srcFolderName+"（コピー）";//コピー先の最上位フォルダだけ識別しやすくする

  var newFolder = dstFolder.createFolder(dstFolderName)
  Logger.log(newFolder.getName());
  copy(srcFolder, newFolder);//コピー元，コピー先

}

function copy(srcFolder, newFolder){
  var srcFiles = srcFolder.getFiles();//フォルダ内ファイルをゲット
  while(srcFiles.hasNext()) {
    var srcFile = srcFiles.next();
    Logger.log(srcFile.getName());
    srcFile.makeCopy(srcFile.getName(), newFolder);
  }
  var srcFolders = srcFolder.getFolders();//フォルダ内フォルダをゲット
  while(srcFolders.hasNext()) {
    var nextSrcFolder = srcFolders.next();
    Logger.log(nextSrcFolder.getName());
    var nextNewFolder = newFolder.createFolder(nextSrcFolder.getName());
    copy(nextSrcFolder, nextNewFolder);//再帰
  }
}
```

　実際の開発画面は次の通りです。参考にしてください。
![7.png](https://qiita-image-store.s3.amazonaws.com/0/146927/22717e6b-e41d-b5c4-b832-fdd0f6a2f1a8.png)

　ここで，「Ssheet.gs」の内容が必要になりますが，これはSpreadseatを扱う自作のクラスです。メンバ関数のすべてが必要ではないのですが，すべてリストしておきます。「Ssheet.gs」は，「ファイル」「新規作成」「スクリプトファイル」で，ファイル名として「Ssheet」を指定します。拡張子「.gs」は勝手に付きます。

```javascript:Ssheetクラス
//////////Ssheetクラスの定義開始（コンストラクタとメンバ関数で構成）
//Ssheetクラスのコンストラクタの記述
Ssheet = function(id){
  this.id = id;
  this.ssFile = SpreadsheetApp.openById(id);
  this.ssFileName = this.ssFile.getName();
  SpreadsheetApp.setActiveSpreadsheet(this.ssFile);//値を返さない
  this.activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
}
//Ssheetクラスのメンバ関数（メソッド）の定義開始
//spreadsheetのファイル名を返すメソッド
Ssheet.prototype.getFileName = function(){
  return this.ssFileName;
}
//spreadsheetのファイル名を変更するメソッド
Ssheet.prototype.rename = function(newName){
  this.ssFile.rename(newName);
}
//spreadsheetのsheetでrow行cal列にデータを入れるメソッド
Ssheet.prototype.setValue = function(sheet,row,col,value){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.setValue(value);
}
//spreadsheetのsheetでrow行cal列を数値形式にセットするメソッド
Ssheet.prototype.setStdNumFmt = function(sheet,row,col,value){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.setNumberFormat("0");
}
//spreadsheetのsheetでrow行cal列をクリアするメソッド
Ssheet.prototype.clear = function(sheet,row,col,value){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.clear(value);
}
//spreadsheetのsheetからrow行のcal列のデータをもらってくるメソッド
Ssheet.prototype.getValue = function(sheet,row,col) {
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var value = this.activeSheet.getRange(row, col).getValue();
  return value;
}
//背景の色を設定するメソッド
Ssheet.prototype.setBackgroundColor = function(sheet,row,col, r,g,b) {
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.setBackgroundRGB(r,g,b);
}
//spreadsheetのsheet数を指定の数増やすメソッド
Ssheet.prototype.insertSheet = function(num){
  var sheetNum = this.activeSpreadsheet.getNumSheets();
  while(num>sheetNum){
    this.activeSpreadsheet.insertSheet();
    sheetNum++;
  }
}
//spreadsheetの指定sheetを削除
Ssheet.prototype.deleteSheet = function(sheet){
  this.activeSpreadsheet.deleteSheet(this.activeSpreadsheet.getSheets()[sheet])
}
//spreadsheetのsheetの名前をセットするメソッド
Ssheet.prototype.renameSheet = function(sheet,newName){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.setName(newName);
}
//spreadsheetの指定sheetの全データを取得
Ssheet.prototype.getValues = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet.getDataRange().getValues();//シートの全データを取得
}  
//spreadsheetの指定sheetを取得
Ssheet.prototype.getSheet = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet;//シートを返す
}
//spreadsheetの指定sheetの最後の行番号を取得
Ssheet.prototype.getLastRow = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet.getLastRow();//最後の行番号を取得
}
//spreadsheetの指定sheetの最後の列番号を取得
Ssheet.prototype.getLastColumn = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet.getLastColumn();//最後の列番号を取得
}
//spreadsheetの指定行rowを削除
Ssheet.prototype.deleteRow = function(sheet,row){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.deleteRow(row);//行を削除
}
//spreadsheetの指定行rowを挿入
Ssheet.prototype.insertRow = function(sheet,row){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.insertRows(row);//行を挿入
}
//spreadsheetの指定列colを削除
Ssheet.prototype.deleteColumn = function(sheet,col){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.deleteColumn(col);//列を削除
}
//spreadsheetの指定列colを挿入
Ssheet.prototype.insertColumn = function(sheet,col){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.insertColumns(col);//列を挿入
}
//n(0,1,2...)枚目のsheetをアクティブにして，シートのIDを返す
Ssheet.prototype.getSheetIdByNum = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var sheetId = this.activeSheet.getSheetId();
  return sheetId;
}
//////////Ssheetクラスの定義終了
```

　実際には，ごく一部しか使ってないので，下記だけでもokなはずです。下記だけを「コード.gs」の一番下に付け足すだけでもokなはずです。

```javascript:Ssheetクラス
//////////Ssheetクラスの定義開始（コンストラクタとメンバ関数で構成）
//Ssheetクラスのコンストラクタの記述
Ssheet = function(id){
  this.id = id;
  this.ssFile = SpreadsheetApp.openById(id);
  this.ssFileName = this.ssFile.getName();
  SpreadsheetApp.setActiveSpreadsheet(this.ssFile);//値を返さない
  this.activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
}

//spreadsheetのsheetからrow行のcal列のデータをもらってくるメソッド
Ssheet.prototype.getValue = function(sheet,row,col) {
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var value = this.activeSheet.getRange(row, col).getValue();
  return value;
}
```

##実行の方法
　SpreadSheetにコピー元，コピー先のフォルダIDを正しく設定後，次の図のように，「コード.gs」を指定して，関数「folderCopy」を選択し，実行ボタンをクリックします。

![5.png](https://qiita-image-store.s3.amazonaws.com/0/146927/294135b9-1ea9-2891-0d98-eb99d0434cb0.png)

　「実行の承認」のダイアログが表示されたら，承認します。

![8.PNG](https://qiita-image-store.s3.amazonaws.com/0/146927/173af035-3850-4457-2ab1-d91588208076.png)

![9.png](https://qiita-image-store.s3.amazonaws.com/0/146927/69837f78-905b-8574-cca1-b88d85dbbdb5.png)

##アドバイス等
　ご意見・アドバイスなどございましたら，コメント欄にお書きください。