Google Apps Scriptでファイル名、フォルダ名からファイルへアクセスしたい

Google Apps Script（GAS）を使ってファイルへアクセスする場合、ファイルIDやフォルダIDを指定してアクセスする方法は多く紹介されています。Google DriveではファイルIDが分かるとフォルダが異なっていてもファイルへアクセスすることができる点で便利ではあるのですが、作業時にファイル名やフォルダ名から直接アクセスすることができれば都合が良いと思うことがあります。例えば、GASで作成したファイルやGAS経由でアップロードしたファイルについてはその作成時にファイルIDを取得できますが、外部から複数のファイルをGoogle Drive上にドラッグ＆ドロップした場合は、ファイル名は知っていてもIDはファイルを直接確認しないとわかりません。そこで、ファイル名からファイルIDを取得することができると少し便利になると考えました。丁度このような機会があり、少し調べつつ考えてみたところ、他の方々のお役に立つ情報にも繋がればとまとめました。

ここではGASスクリプトを使ってGoogle Drive上にあるファイルに対してファイル名やフォルダ名でアクセスする方法についてできるだけシンプルな方法になるよう検討します。

まず、Google Drive上にあるファイル、フォルダについて分かっていることは次の通りです。

- 全てのファイル、フォルダには個別のIDが付与され、IDを指定することで直接のアクセスができる。
- 同一のファイル名、フォルダ名が同一フォルダ下に複数存在することができる。
- 一つのファイルをフォルダ間で移動させてもファイルIDに変化がないことからファイルIDにはフォルダ情報は含まれていない。
- 2016/8/24の時点ではファイル名、フォルダ名はJISだけでなくSJISも使用することができる。

上記をふまえて次の４通りを考えたいと思います。

1. 同一ファイル名、同一フォルダ名が共に単体しかない場合
1. 同一ファイル名がなく、同一フォルダ名が複数ある場合
1. 同一ファイル名が複数あり、同一フォルダ名がない場合
1. 同一ファイル名、同一フォルダ名が共に複数ある場合

それぞれのサンプルではテキストファイルを開いて中身を見ることを想定しています。
サンプルで使用している変数語尾のIT, IDは、それぞれIterator（反復子）, Identification（識別番号）を意味します。

# 1. 同一ファイル名、同一フォルダ名が共に単体しかない場合
![fig1.jpg](https://qiita-image-store.s3.amazonaws.com/0/133383/3a8d8539-c8ee-a4c8-247f-666deee9fb11.jpeg)

```gas:sample.s
  var file_name = 'file.txt'; // utf8

  var fileIT = DriveApp.getFilesByName(file_name).next();
  var textdata = fileIT.getBlob().getDataAsString('utf8');
```

フォルダを指定せずに直接ファイル名から目的のファイルへアクセスすることが可能です。

# 2. 同一ファイル名がなく、同一フォルダ名が複数ある場合
![fig2.jpg](https://qiita-image-store.s3.amazonaws.com/0/133383/a1efe73f-0044-e03e-a65f-482aa8a814f7.jpeg)

1と同様の方法で特にフォルダを指定することなく、ファイル名を指定して直接目的のファイルへアクセスすることが可能。


# 3. 同一ファイル名が複数あり、同一フォルダ名がない場合
![fig3.jpg](https://qiita-image-store.s3.amazonaws.com/0/133383/c706cfa1-479a-1dd1-c8d3-1ebc43bfe772.jpeg)

```gas:sample.s
  var file_name = 'file.txt'; // utf8
  var folder_name = 'folder';

  var folderID = DriveApp.getFoldersByName(folder_name).next().getId();
  var fileIT = DriveApp.getFolderById(folderID).getFilesByName(file_name).next();
  var textdata = fileIT.getBlob().getDataAsString('utf8');
```

- 同一名のファイルがそれぞれ別のフォルダ下にある場合、フォルダを指定することで上記サンプルのようにそのフォルダ下の目的のファイルへファイル名指定でアクセスすることが可能。

![fig3b.jpg](https://qiita-image-store.s3.amazonaws.com/0/133383/30134234-5c1c-74e3-211b-a895c6857d31.jpeg)

- 同一名のファイルが一つのフォルダ下にある場合、フォルダの指定は不要ですが、目的のファイルへアクセスするためにはそれぞれのファイルのIDを確認し、ID指定でアクセスする必要がある。


# 4. 同一ファイル名、同一フォルダ名が共に複数ある場合
![fig4.jpg](https://qiita-image-store.s3.amazonaws.com/0/133383/a21fbd04-f6aa-0324-6f84-b4f6e4e11660.jpeg)

- 同一名のファイルが複数あり、それぞれの単体ファイルが別々且つ同一名のフォルダ下にある場合、フォルダをID指定することでそのフォルダ下にある目的のファイルへファイル名指定でアクセスすることが可能。

![fig5.jpg](https://qiita-image-store.s3.amazonaws.com/0/133383/8545684f-1d5e-aff9-940a-5564f614eba3.jpeg)

- 一つのフォルダへ同一名のファイルが複数入っており、さらにこのようなファイルの入ったフォルダが複数あり、且つ、フォルダ名が同一であるような場合は、ファイルID指定でアクセスするほうがよりシンプル。この場合フォルダ指定は不要。なかなかこのような状況はないかと思われますが。


# 結論

結果として、1や2のように同一名のファイルがない場合、ファイル名指定でシンプルにアクセスすることができます。ID自体が唯一無二のものなので、ファイル名やフォルダ名も同様に唯一無二にすることでIDではなくファイル名やフォルダ名でのアクセスができます。

また、特定のフォルダへ新たにファイルを作成する場合はフォルダ指定は必須です。既にできたファイルへアクセスする際は状況によってフォルダを指定することなくファイル名のみでのアクセスが可能です。（おまけ(A1)）

今回上記のように検討しているなかで、同一名のファイルやフォルダの数を確認する方法もあるのではとおまけ(A2)のように考えてみました。

本結果の他にも良い案はあるかと思いますが、私の現在の知識では上記のような結論です。今後の経験でさらに良い案が見つかりましたらご報告したいと思います。


# おまけ

## (A1)特定のフォルダへ特定のファイルを作成してアクセス

```gas:sample.s
  var file_name = 'file.txt';
  var folder_name = 'folder';
  var data = 'いろはにほへと';

  var folderIT = DriveApp.getFoldersByName(folder_name).next();
  var fileIT = folderIT.createFile(file_name, data, MimeType.PLAIN_TEXT); // デフォルト文字コード utf8

  Logger.log(fileIT.getBlob().getDataAsString()); // いろはにほへと
```

サンプルのようにファイルを作成する際は特定のフォルダ名を指定してそのフォルダ下にファイルを作成していますが、作成時にファイルイテレータを取得しますので、アクセスする際はフォルダを指定せずとも作成したファイルへのアクセスが可能です。


## (A2)同一名のフォルダ、ファイルの数を出力

```gas:sample.s
function F_number(file_name, folder_name) {
  var Array_files = [];
  var Array_folders = [];

  var fileIT = DriveApp.getFilesByName(file_name);
  while (fileIT.hasNext()) {
    Array_files.push(fileIT.next().getId());
  };

  var folderIT = DriveApp.getFoldersByName(folder_name);
  while (folderIT.hasNext()) {
    Array_folders.push(folderIT.next().getId());
  };
  return [Array_files.length, Array_folders.length];
}
```

今回検討した内容を用いて、指定したファイル、フォルダと同じファイル名、フォルダ名がいくつあったかを確認するスクリプトを用意してみました。これについてはスクリプトのアウトプットに対して決して最適なプロセスではないと思われます。文字列としてファイル名、フォルダ名を入力すると、入力したものと同じ名前のものがあればその個数を出力します。指定したファイル名、フォルダ名が存在しない場合は0が返ります。