Google Drive API v3 を C# で使ってみた まとめ

# はじめに
Google Drive API v3 を.Net C#から触っているサンプルがあまり見つけられなかったのでメモ。

FF14向けActの設定自動バックアップソフトを作ろうと思い立った事が使う事になったきっかけ。

ソースは以下で公開しています。
~~[JuscoBot](https://github.com/iwatuki/JuscoBot) (こっちはFF14のプラグイン)~~
[GoogleDriveAPI.cs](https://github.com/iwatuki/GDSync/blob/master/GoogleAPI/GoogleDriveAPI.cs)

まだ調べられていない事も結構あるので分かり次第追記していきます。

# 環境構築とか

以下の通りにサンプル実行まで
[.Net Quickstart](https://developers.google.com/drive/api/v3/quickstart/dotnet)

# やりたい事

### フォルダ内同期
一番やりたい事だったけど専用のそういうAPIは存在しないっぽいので地道に作るしかない？
(簡単な方法知ってる方いたら教えて下さい)

```
(簡単なやり方募集中)
```

### フォルダ作成
mimeTypeをフォルダにして作る。サブフォルダを作る場合は親フォルダのIDを入れて作成

```
	File meta = new File();
	meta.Name = "folder Name";
	meta.MimeType = "application/vnd.google-apps.folder";
	meta.Parents = new List<string> { parentFolderId }; // 特定のフォルダのサブフォルダとして作成する場合
	var request = service.Files.Create(meta);
	request.Fields = "id, name"; // ただ作るだけならこの行不要
	var file = await request.ExecuteAsync();
```

### ファイル・フォルダ検索
以下の request.Q に取得したい条件のクエリを入れて検索で大体取れる


```
	string nextPageToken = null;
	do {
		FilesResource.ListRequest request = service.Files.List();
		request.PageToken = nextPageToken;
		request.Q = "'file.txt' and trashed = false"; // 名前が file.txt に一致, ゴミ箱は検索しない
		request.Fields = "nextPageToken, files(id, name)";
		var result = await request.ExecuteAsync();
		if (result.Files.Count > 0) return result.Files[0];
		nextPageToken = result.NextPageToken;
	} while (!string.IsNullOrEmpty(nextPageToken));
```


#### (参考)クエリに書ける条件式

[Query Reference](https://developers.google.com/drive/api/v3/reference/query-ref)
[Search for files and folders](https://developers.google.com/drive/api/v3/search-files)

```
// フォルダのみを検索
var onlyFolderQuery = "mimeType = 'application/vnd.google-apps.folder'";
// ファイルのみを検索
var onlyFileQuery = "mimeType != 'application/vnd.google-apps.folder'";

// 特定のフォルダ配下のファイル
var subFolderQuery = "'folder name' in parents"; // ファイル名
var subFolderQuery = "'folder id' in parents"; // ファイルIDでもOK
```

### Fields に書ける内容
FileListクラスのプロパティが書けるイメージ

FileListクラスのプロパティ
[Google.Apis.Drive.v3.Data.FileList Class Reference](https://developers.google.com/resources/api-libraries/documentation/drive/v3/csharp/latest/classGoogle_1_1Apis_1_1Drive_1_1v3_1_1Data_1_1FileList.html)

配下のFileクラスはFileListクラスにネストされているので以下のような書き方

Fileクラスのプロパティ
[Google.Apis.Drive.v3.Data.File Class Reference](https://developers.google.com/resources/api-libraries/documentation/drive/v3/csharp/latest/classGoogle_1_1Apis_1_1Drive_1_1v3_1_1Data_1_1File.html)

```
request.Fields = "nextPageToken, files(id, name, createdTime, mimeType)";
```

### ファイルアップロード

```
	var meta = new File() {
		Name = System.IO.Path.GetFileName(filePath),
		MimeType = GetMimeType(filePath)
	};
	if (parentId != null) meta.Parents = new List<string> { parentId };

	using (var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Open)) {
		// 新規追加
		var request = service.Files.Create(meta, stream, GetMimeType(filePath));
		request.Fields = "id, name";
		var result = await request.UploadAsync();
		return request.Body;
	}
```

```
	private static string GetMimeType(string fileName) {
		string mimeType = "application/unknown";
		string ext = System.IO.Path.GetExtension(fileName).ToLower();
		Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
		if (regKey != null && regKey.GetValue("Content Type") != null)
			mimeType = regKey.GetValue("Content Type").ToString();
		return mimeType;
	}
```

### ファイル上書き・ファイルリネーム (その他情報修正)

```
	using (var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Open)) {
		File file = new File();
		file.Name = "test2.txt"; // リネームしたいファイル名に
		file.Description = "変更したいファイルの説明"; // 変更したいファイルの説明
		// originalFileId は変更したい元ファイルのID
		var request = service.Files.Update(file, originalFileId, stream, GetMimeType(filePath));
		await request.UploadAsync();
		return request.ResponseBody;
	}
```

### ファイル削除

```
	var request = service.Files.Delete(fileId);
	await request.ExecuteAsync();
```

### ファイルダウンロード
対象のfileIdを指定してダウンロード

```
	var request = service.Files.Get(fileId);
	var stream = new System.IO.FileStream(savePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
	var progress = request.DownloadAsync(stream);
	await ProgressTask(progress, OnProgress, progressIntervalMillisec); // ダウンロード進捗を取得できるようprogressを返す
	return progress.Result;
```

### ドライブ上で変更されたファイル一覧取得
同期するまで changeToken は何かしらの方法で保存しておく

```
	public List<Change> Diff(ref string changeToken, SpaceName space = SpaceName.appDataFolder, int page = -1) {
		if (changeToken == null) changeToken = service.Changes.GetStartPageToken().Execute().StartPageTokenValue;
		List<Change> changeList = new List<Change>();
		bool allPage = (page < 0);
		while (changeToken != null && (allPage || page > 0)) {
			var request = service.Changes.List(changeToken);
			request.Spaces = space.ToString();
			var changes = request.Execute();
			changeList.AddRange(changes.Changes);
			changeToken = changes.NextPageToken;
			page--;
		}
		return changeList;
	}
```