Help us understand the problem. What is going on with this article?

Google Apps ScriptでGoogle Driveのフォルダ構造を含んだファイルリストを作成する

More than 1 year has passed since last update.

モノを作成しているとき、Google Apps Script (GAS)を使用する箇所でも時々フォルダやファイルのリストが必要になる場合があります。ドライブ内の特定のフォルダ下のファイルリストやフォルダ構造も必要になる場合があります。これまではその都度用意していたのですが、このような状況が増えてきたことから、モノを作る際に少しでも手間を省こうと考えてここで紹介させていただくライブラリを作成しました。また、最近、フォルダ構造の情報を含んだファイルリストの取得に関する問い合わせが増えていることもあり、他の方々に対してもお役に立てることができればと思い公開させていただきました。

ライブラリの本体はGitHubでご覧いただけます。

ライブラリのプロジェクトキー

1dBxqh6gpWqFv4h0M25ALp4bhcs6CoqhiIJ0fUeUjR57bAxIN2PqfkQns

インストール方法

  1. 最初にスクリプトディタを立ち上げてライブラリをインストールします。インストール方法はこちらをご覧ください。
    • このとき使用するライブラリのプロジェクトキーは、1dBxqh6gpWqFv4h0M25ALp4bhcs6CoqhiIJ0fUeUjR57bAxIN2PqfkQnsです。
  2. 次にAPIコンソールでDrive APIを有効にします。
    • スクリプトエディタの「リソース」 -> 「Cloud Platformプロジェクト」を開きます。
    • 「このスクリプトが現在関連付けられているプロジェクト:」の下のリンクをクリックします。
    • 「スタートガイド」の「API を有効化し、鍵などの認証情報を取得」をクリックします。
    • ダッシュボードにDrive APIが見えている場合はそれをクリックします。見えていない場合は、左側のサイドバーにある「ライブラリ」をクリックします。
    • 「APIとサービスを検索」へ Drive API と入力して検索します。
    • 表示された中からDrive APIをクリックします。
    • ここでDrive APIを有効にします。ボタンをクリックしてから少しの待ち時間があります。

(注意)少し前はライブラリの中にDriveAppを使用する箇所があればスクリプトエディタによって自動でDrive APIが有効になっていたのですが、最近仕様が変わったようでライブラリ内のDriveAppは無視されるようになったため、手動で設定する必要があります。

使い方

用意したメソッドは次の4つです。今のところ、自分で使用している状況と問い合わせで多かった項目を合わせて4種類を用意しました。

メソッド 内容
createTree(folderId, mimeType, fields) folderIdで指定したフォルダ下の全階層のファイル、フォルダリストを構造付きで取得
getAllInFolder(folderId, mimeType, fields) folderIdで指定したフォルダ下の全ファイルを構造は無視して取得
getAllFoldersInFolder(folderId) folderIdで指定したフォルダ下の全階層のフォルダリストを取得
getFilesAndFoldersInFolder(folderId, mimeType, fields) folderIdで指定したフォルダ直下の全ファイルを取得
  • fileId : 検索する際のトップフォルダのIDです。例えばこれを"root"とすると、全てのファイルやフォルダを取得することができます。
  • mimeType : ファイルを取得する際のmimeTypeをここで指定します。1次元配列として、例えば["application/vnd.google-apps.script", "image/png"]のように与えてください。また、mimeTypeをnullにすることで全ての種類のファイルを取得します。
  • fields : Drive APIのfiles.listで使用するfieldsと同じものを使用することができます。例えばファイル名のみを取得したい場合は、"files(id,name)"を与えてください。

サンプル

サンプルとして下図のようなフォルダ構造を想定して各メソッドの使い方とそのレスポンスについて記載します。

fig1.png

1. createTree(folderId, mimeType, fields)

folderId, mimeType, fields へそれぞれ"sampleFolder1"のID, null, files(name) を与えます。

var res = FilesApp.createTree(folderId, null, "files(name)");
レスポンス

folderIdで与えたフォルダ以下の全てのファイル、フォルダを取得するとともに、それぞれのファイルがフォルダ構造のどこにあるかの情報も同時に取得します。また、folderTreeByIdfolderTreeByNameの配列のインデックスはフォルダ構造の深さに対応しています。値が大きくなるほど深いことを意味します。

{
  "topFolderId": ["### FolderId of sampleFolder1 ###"],
  "topFolderName": ["sampleFolder1"],
  "totalFilesAndFolders": 11,
  "totalFiles": 4,
  "totalFolders": 7,
  "files": [
    {
      "folderTreeById": ["### FolderId of sampleFolder1 ###"],
      "folderTreeByName": ["sampleFolder1"],
      "filesInFolder": [
        {
          "name": "Spreadsheet1",
          "parents": ["### FolderId of sampleFolder1 ###"]
        },
        {
          "name": "sampleFolder_2b",
          "parents": ["### FolderId of sampleFolder1 ###"]
        },
        {
          "name": "sampleFolder_2a",
          "parents": ["### FolderId of sampleFolder1 ###"]
        }
      ]
    },
    {
      "folderTreeById": ["### FolderId of sampleFolder1 ###", "### FolderId of sampleFolder_2b ###"],
      "folderTreeByName": ["sampleFolder1", "sampleFolder_2b"],
      "filesInFolder": [
        {
          "name": "Spreadsheet4",
          "parents": ["### FolderId of sampleFolder_2b ###"]
        },
        {
          "name": "sampleFolder_2b_3b",
          "parents": ["### FolderId of sampleFolder_2b ###"]
        },
        {
          "name": "sampleFolder_2b_3a",
          "parents": ["### FolderId of sampleFolder_2b ###"]
        }
      ]
    },
    {
      "folderTreeById": ["### FolderId of sampleFolder1 ###", "### FolderId of sampleFolder_2b ###", "### FolderId of sampleFolder_2b_3b ###"],
      "folderTreeByName": ["sampleFolder1", "sampleFolder_2b", "sampleFolder_2b_3b"],
      "filesInFolder": [
        {
          "name": "sampleFolder_2b_3b_4a",
          "parents": ["### FolderId of sampleFolder_2b_3b ###"]
        }
      ]
    },
    {
      "folderTreeById": ["### FolderId of sampleFolder1 ###", "### FolderId of sampleFolder_2b ###", "### FolderId of sampleFolder_2b_3b ###", "### FolderId of sampleFolder_2b_3a ###"],
      "folderTreeByName": ["sampleFolder1", "sampleFolder_2b", "sampleFolder_2b_3b", "sampleFolder_2b_3b_4a"],
      "filesInFolder": [
        {
          "name": "Spreadsheet5",
          "parents": ["### FolderId of sampleFolder_2b_3a ###"]
        }
      ]
    },
    {
      "folderTreeById": [ "### FolderId of sampleFolder1 ###", "### FolderId of sampleFolder_2b ###", "### FolderId of sampleFolder_2b_3a ###"],
      "folderTreeByName": ["sampleFolder1", "sampleFolder_2b", "sampleFolder_2b_3a"],
      "filesInFolder": [
        {
          "name": "Spreadsheet3",
          "parents": ["### FolderId of sampleFolder_2b_3a ###"]
        }
      ]
    },
    {
      "folderTreeById": ["### FolderId of sampleFolder1 ###", "### FolderId of sampleFolder_2a ###"],
      "folderTreeByName": ["sampleFolder1", "sampleFolder_2a"],
      "filesInFolder": [
        {
          "name": "Spreadsheet2",
          "parents": ["### FolderId of sampleFolder_2a ###"]
        },
        {
          "name": "sampleFolder_2a_3a",
          "parents": ["### FolderId of sampleFolder_2a ###"]
        }
      ]
    },
    {
      "folderTreeById": ["### FolderId of sampleFolder1 ###", "### FolderId of sampleFolder_2a ###", "### FolderId of sampleFolder_2a_3a ###"],
      "folderTreeByName": ["sampleFolder1", "sampleFolder_2a", "sampleFolder_2a_3a"],
      "filesInFolder": []
    }
  ]
}

2. getAllInFolder(folderId, mimeType, fields)

var res = FilesApp.getAllInFolder(folderId, null, "files(name)");
レスポンス

folderIdで与えたフォルダ以下の全てのファイル、フォルダを取得します。このメソッドではフォルダ構造は無視して取得します。このため、速度はcreateTree()よりも少し速いです。

[
    {"name":"Spreadsheet5"},
    {"name":"Spreadsheet4"},
    {"name":"Spreadsheet3"},
    {"name":"Spreadsheet2"},
    {"name":"Spreadsheet1"},
    {"name":"sampleFolder_2b_3b_4a"},
    {"name":"sampleFolder_2a_3a"},
    {"name":"sampleFolder_2b"},
    {"name":"sampleFolder_2a"},
    {"name":"sampleFolder_2b_3b"},
    {"name":"sampleFolder_2b_3a"}
]

3. getAllFoldersInFolder(folderId)

var res = FilesApp.getAllFoldersInFolder(folderId);
レスポンス

folderIdで与えたフォルダ以下の全てのフォルダをフォルダ構造の情報を含めて取得します。

{
    "id":[
        ["### ID of sampleFolder1 ###"],
        ["### ID of sampleFolder1 ###","### ID of sampleFolder_2b ###"],
        ["### ID of sampleFolder1 ###","### ID of sampleFolder_2b ###","### ID of sampleFolder_2b_3b ###"],
        ["### ID of sampleFolder1 ###","### ID of sampleFolder_2b ###","### ID of sampleFolder_2b_3b ###","### ID of sampleFolder_2b_3b_4a ###"],
        ["### ID of sampleFolder1 ###","### ID of sampleFolder_2b ###","### ID of sampleFolder_2b_3a ###"],
        ["### ID of sampleFolder1 ###","### ID of sampleFolder_2a ###"],
        ["### ID of sampleFolder1 ###","### ID of sampleFolder_2a ###","### ID of sampleFolder_2a_3a ###"]
    ],
    "name":[
        ["sampleFolder1"],
        ["sampleFolder1","sampleFolder_2b"],
        ["sampleFolder1","sampleFolder_2b","sampleFolder_2b_3b"],
        ["sampleFolder1","sampleFolder_2b","sampleFolder_2b_3b","sampleFolder_2b_3b_4a"],
        ["sampleFolder1","sampleFolder_2b","sampleFolder_2b_3a"],
        ["sampleFolder1","sampleFolder_2a"],
        ["sampleFolder1","sampleFolder_2a","sampleFolder_2a_3a"]
    ]
}

4. getFilesAndFoldersInFolder(folderId, mimeType, fields)

var res = FilesApp.getFilesAndFoldersInFolder(folderId, null, "files(name)");
レスポンス

folderIdで与えたフォルダの直下にある全てのファイル、フォルダを取得します。この場合、全階層ではありません。

[
    {"name":"Spreadsheet1"},
    {"name":"sampleFolder_2b"},
    {"name":"sampleFolder_2a"}
]

工夫したところ

与えたフォルダ下の全階層のフォルダ構造を取得した後、このリストを使って全ファイルを構造付きで取得する際の方法について少し迷いました。まず、ファイル数が多くなると理由は不明ですがDriveAppでは速度が非常に遅くなりましたのでDrive APIを直接使用することにしました。迷った部分は次の2点です。

  • Drive APIのfiles.listを使ってDrive内の全ファイルを取得した後にフォルダリストを使って各フォルダ下のファイルを取得する。
  • files.listのqを使ってフォルダリストにあるフォルダ内のファイルだけを取得する。

結果として後者を選択しました。理由は、実際に使用する場合を想定すると、全ファイルを検索する状況よりも、ある特定のフォルダ下の情報を取得する場合が多かったからです。例えば、前者の場合、指定したフォルダにファイルが1つしかなくても、全ファイルを読み込むことになり余計なAPIと時間のロスが発生してしまいます。一方、ルートから全ファイルを取得する場合では前者の方がAPI消費量として効率は高いです。しかし、この不利についてはバッチリクエストを採用することで後者でもより少ないAPIと時間のロスを実現できたことで解決しました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした