Google Drive API v3で特定のフォルダ以下のファイルを再帰的に取得する

はじめに

タイトルの通りGoogle Driveで特定のディレクトリ以下のファイル一覧とそのファイルのオーナー情報を取得したかった

ただし、ネットで調べるとv2での情報が多く思ったよりも嵌ったのでメモがてら残して置く

コードの一部

コードの一部はこんな感じ (書き捨てのscriptだったので所々適当になっているが、そこはご愛嬌で…)

Google Drive Clientを取得する部分は省きました

Google Drive Clientの取得部分はGoogle Ddriveの公式ドキュメントにサンプルが載っているのでそっちを参考にしてもらえればと。

import (
	"fmt"
	"log"
	"strings"

	"google.golang.org/api/drive/v3"
)

func getFileListWithNextPageTokenAndOwnerID(srv *drive.Service, token, ownerID string) (*drive.FileList, error) {
	return srv.Files.List().
	Fields("nextPageToken, files(parents, id, name, owners, kind, mimeType)").
	Q(fmt.Sprintf("'%s' in parents", ownerID)).
	PageToken(token).
	Do()
}

func listDriveInfo(srv *drive.Service, list *drive.FileList, root []string) {
	for _, f := range list.Files {
		owners := []string{}
		for _, o := range f.Owners {
			owners = append(owners, o.EmailAddress)
		}

		parents := []string{}
		for _, p := range f.Parents {
			name, ok := idAndName[p]
			if !ok {
				name = p
			}
			parents = append(parents, name)
		}

		if f.MimeType == "application/vnd.google-apps.folder" {
			idAndName[f.Id] = f.Name
			//log.Printf("%+v", f)
			r := append(root, parents...)
			l, err := getFileListWithNextPageTokenAndOwnerID(srv, list.NextPageToken, f.Id)
			if err != nil {
				//log.Println("error get list", err.Error())
				continue
			}
			listDriveInfo(srv, l, r)
		}
		log.Printf("%s/%s,%s,\"%s\"\n", strings.Join(root, "/"), f.Name, f.Id, strings.Join(owners, ","))
	}
}

コードの説明

  return srv.Files.List().
	Fields("nextPageToken, files(parents, id, name, owners, kind, mimeType)").
	Q(fmt.Sprintf("'%s' in parents", ownerID)).
	PageToken(token).
	Do()

v2まではファイルに関する情報すべてが返ってきていたがv3から必要最低限の情報しか返えらなくなってしまった。

何も指定しなくても kind, id, name, mimeType は返ってくる(っぽい)

今回はparents(親ディレクトリ情報), owners(オーナー情報)を取得するようにしたのでこんな感じでFieldsを指定している

また再帰的に取得したかったのでQパラメータで親ディレクトリを指定した形になっている

Qパラメータではもう少し複雑なクエリを設定できる模様

parents := []string{}
for _, p := range f.Parents {
  name, ok := idAndName[p]
  if !ok {
    name = p
  }
	parents = append(parents, name)
}

v2ではnameがフルパス(?)で取得できた気がするが今はファイルの名前しか返ってこなくなったのでフルパスでファイル名を表示したかったのでparentsとしてディレクトリのパスを配列で渡してあげる形にした。

l, err := getFileListWithNextPageTokenAndOwnerID(srv, list.NextPageToken, f.Id)
  if err != nil {
  //log.Println("error get list", err.Error())
  continue
}

あとは末端?(ディレクトリが存在しない)ディレクトリに対してファイル一覧のAPIをコールするとエラーになるのでerrを無視している

もう少しスマートなやり方はあるはず…

おわりに

雑な感じだけどこんな感じで再帰的にファイル一覧が取得できたのでめでたしめでたし🎉

参考URL

みんなのGo言語【現場で使える実践テクニック】
松木雅幸 mattn 藤原俊一郎 中島大一 牧 大輔 鈴木健太
技術評論社
売り上げランキング: 137,918