Google Driveのフォルダを再帰的にコピーする

Google Drive (Google One) のファイルを Google Workplace (旧 G Suite)にコピーしようとしたが、階層全体をコピーするコマンドがない。

コピーするファイル量が多くないときは、ローカルのPCにダウンロードして、それを移動先にコピーすることをしていたが、そこそこの量があるので、Google内で終わらせたいと思った。

背景

他のアカウントが所有するファイル群を自分のGoogle Driveで共有しているものがあり、それをGoogle Workplaceにコピーしたい。共有しているフォルダをGoogle Workplaceでも共有してアクセスすることはできるが、他のアカウントは操作できないのでファイルの所有権を渡す方法がとれない。

自分のGoogle Driveにコピーができれば、自分のアカウント間のGoogle Drive から Google Workplaceに共有と所有権移動ができるはず。そこで、Google Drive内でフォルダの再帰的コピーができる機能が必要となった。

調査

検索をして以下のWebを参考にして試してみたが、Google Apps Scriptの実行時間の上限を超えてしまい、コピーが完了しなかった。

Google Drive:フォルダ丸ごとコピー:フォルダ階層下のすべてのファイル・フォルダを同じフォルダ構造のまま一度にコピー(GoogleFormでのメニュー付き)

ファイルのコピー自体に時間がかかっているだろうから、まず、コピーすべきファイルのリストを作成しておいて、実際のファイルのコピーはリストに従って何回かに分けてスクリプトで実行すれば良いのではないかと思って、そのようなGoogle Apps Script を作成してみた。しかし、実行時間制限が厳しすぎてリストの作成がそもそも制限時間内に終わらなかった。

コピー処理の履歴を残して、再開できるプログラムが必要であることがわかった。

そこで、再帰的にコピーし、再開できるGoogle Apps Scriptを作成することにした。

再帰的コピーのためのスクリプト作成

フォルダの階層を再帰的にコピーするスクリプトを作成してみた。

一応動作しているが遅い。Spreadsheetを履歴管理に使っていて、Google Apps Scriptのプログラミングも初めてで効率が悪いスクリプトであろうこともあるが遅い。6分(360秒)の実行制限時間内に1MB弱のファイルを200ほどしかコピーできない。

時間制限があることから、全体を何度も実行する必要があり、あまり実用的ではない。

手間をかけないのは、NASで自動的にダウンロードして、それを自動的にアップロードして、コピーすることのようだ。時間はかかるにしても休みなく働いてくれるので手間は少なそうである。

再帰的にコピーするスクリプト

せっかく作ったので備忘録としてスクリプトを残しておく。

簡単な動作確認をしているが、制限時間でスクリプトが中断された時の扱いが問題ないか十分には検証していない。あくまでも備忘録として記録しておくものであり、このスクリプトを利用した結果に不具合があっても責任はとれない。もしも使うなら At your own riskでお願いする

管理データの構造

ソース側のフォルダのId (+".xlsx")を名前とするスプレッドシートに複製すべきファイルやフォルダのリストとその完了状況を記録する。

列には、ソースの名前(name)、ソースファイルのID(srcFileId)、ソースフォルダのID(srcFolderId)、デスティネーションのID(dstId)、デスティネーションの名前(dstName)、完了時刻(timestamp) を記録する。timestamp が空の場合にはコピー処理が完了していないことを表す。

srcFileId と srcFolderIdはどちらかしか使われず、それによってソースがファイルかフォルダかを区別する。

dstNameはソースの名前と同じはずなので不要であるが、デバッグのために使った。

行が1つのファイルもしくはフォルダを表す。

最終行のname列に "*" が記録されている場合には、そのシート全体、つまり、シートに対応するソースフォルダの処理が完了していることを意味する。

処理の考え方

startCopy を実行することでソースフォルダ内にあるファイルやフォルダをデスティネーションフォルダ内に複製する。

sourceRootFolderName にソースフォルダ名を指定する。
destinationRootFolderName にデスティネーションフォルダ名を指定する。
workFolderName に作業用フォルダ名を指定する。作業用フォルダ内に管理用のスプレッドシートファイルが作成される。

startCopy

startCopyは初期化を行った後に、traverseを呼び出す。

traverse

traverseは、ソースフォルダに対応するスプレッドシートをmakeSpreadsheetFileで作成し、processSpreadsheetFileで処理する。

makeSpreadsheetFile

makeSpreadsheetFileは、ソースフォルダにあるファイルの名前とID (srcFileId) をスプレッドシートに記録する。

次に、ソースフォルダにある子フォルダと同じ名前のフォルダをデスティネーションフォルダに作成し、ソースフォルダの名前とID (srcFolderId)、デスティネーションフォルダのID (dstId)と名前(dstName) をスプレッドシートに記録する。

processSpreadsheetFile

processSpreadsheetFileは、スプレッドシートに記録されている行で、タイムスタンプが空の行を上から順に処理していく。スプレッドシートに記録されているデータを基にファイルのコピーや再帰的な処理を行う。

ソースがファイルの場合には、デスティネーションフォルダにファイルをコピーして、コピーが完了したら、その日時をスプレッドシートのtimestampに記録する。

ソースがフォルダの場合には、traverseを利用して再帰的に処理を行う。

スクリプト

テスト実行

ファイル階層

次の図ような構造のフォルダをコピーしてみた。「+」がフォルダを表し、「-」がファイルを表す。

生成されるスプレッドシートファイル

実行が完了すると作業フォルダの tmp に以下のようなファイルができている。それぞれのファイルがフォルダの管理情報を含んでいる。

実行が終わった後のスプレッドシートの内容は以下の通りである。

src に対応するスプレッドシート

child1 に対応するスプレッドシート

child2 に対応するスプレッドシート

ログ出力

スクリプト実行時のログは次の通り。