【Google Apps Script (GAS)】Googleフォームでアップロードするファイルのファイル名を変更する方法
Googleフォームにてファイルをアップロードすることができます。
アップロードしたファイルはGoogleドライブに保存されますが、この時のファイル名をアップロードと同時に変更してしまおうというのが今回紹介するスクリプトの処理内容です。
例として、動画をアップロードし、アップロードしたファイルのファイル名を「氏名 + 年月日時分秒」のファイル名に変換するようにします。
Googleフォームを準備
まずはGoogleフォームを準備します。
作成方法についてはこちらの記事を参照ください。
入力欄としては「氏名」と「動画のアップロード欄」を用意します。
準備ができたら、「スクリプトエディタ」を開き、スクリプトを記述します。
スクリプトエディタでスクリプトを記述する
右上の「その他」メニューからスクリプトエディタを選択し、エディタ画面を開きます。
「myFunction」という関数の中に下記の処理を記述します。
Googleフォームから回答情報を受け取るために「myFunction」の引数にeを追加します。
function myFunction(e) {
var itemResponse;
var fileName;
var movie;
//回答のオブジェクトを取得
var itemResponses = e.response.getItemResponses();
// お名前の回答結果を取得する
itemResponse = itemResponses[0];
fileName = itemResponse.getResponse() + '_' + dateToStr24HPad0(new Date(), 'YYYYMMDDhhmmss');
// 投稿動画の回答結果を取得する
itemResponse = itemResponses[1];
movie = DriveApp.getFileById(itemResponse.getResponse());
movie.setName(fileName);
}
/**
* 日付をフォーマットする
*/
function dateToStr24HPad0(date, format) {
if (!format) {
// デフォルト値
format = 'YYYY/MM/DD hh:mm:ss'
}
// フォーマット文字列内のキーワードを日付に置換する
format = format.replace(/YYYY/g, date.getFullYear());
format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
return format;
}
日付をフォーマットする処理を関数化(15行目:dateToStr24HPad0())して見やすくしています。
処理の解説
処理の流れは、
「回答データを取得する」
↓
「回答データから氏名を取得する」
↓
「氏名 + 年月日時分秒をfileNameの変数に格納する」
↓
「回答データから動画を取得する」
↓
「動画のファイル名をfileName(氏名 + 年月日時分秒のこと)に変更する」
となっています。
回答データを取得する
//回答のオブジェクトを取得
var itemResponses = e.response.getItemResponses();
e.response.getItemResponses()でフォームの「お名前」「投稿動画」の回答を配列で取得しています。
回答データから氏名を取得する
// お名前の回答結果を取得する
itemResponse = itemResponses[0];
回答データの配列[0]に「お名前」に関する回答結果が格納されているのでそれを取得します。
氏名 + 年月日時分秒をfileNameの変数に格納する
var fileName;
:
:
fileName = itemResponse.getResponse() + '_' + dateToStr24HPad0(new Date(), 'YYYYMMDDhhmmss');
処理の先頭で「fileName」という変数を宣言しておき、後にその変数に「氏名 + '_’ + 年月日時分秒」を設定しています。
回答データから動画を取得する
var movie;
:
:
// 投稿動画の回答結果を取得する
itemResponse = itemResponses[1];
movie = DriveApp.getFileById(itemResponse.getResponse());
回答データから氏名を取得すると同じ方法で投稿された動画を取得します。
動画は投稿された時にはGoogleドライブに格納されていますので、itemResponses[1]で取得する際はファイルのIDが取れます。
ファイルIDからDriveAppオブジェクトのgetFileById()メソッドを使って格納された動画ファイルオブジェクトを取得します。
「動画のファイル名をfileName(氏名 + 年月日時分秒のこと)に変更する」
movie.setName(fileName);
最後に取得した動画ファイルのファイル名を変更します。
トリガー設定
トリガーを「フォーム送信時」に実行するように設定することで、動画投稿と同時に「氏名 + 年月日時分秒」のファイル名に変更することができます。
注意点
Appの使用承諾
このプログラムを動作させるには、「DriveApp」と「FormApp」の使用を承諾しないといけません。
DriveAppはトリガー設定時にポップアップで案内が出るので良いのですが、FormAppの方はログを見て初めて気付きました。
FormAppは一度ソースコードに直接「FormApp.create(“")」と書いてしまって承諾した後に削除するとうまくいきます。
1つの設問で複数のファイルをアップロードする対応(2021/05/05追記)
フジイダイスケ様よりコメントいただきました、複数ファイルアップロード時のファイル名変更の対応版です。
ファイル名の変更ルール:お名前_YYYYMMDDhhmmss_連番.拡張子
追加処理として、複数ファイルアップロード時のファイル名変更対応に加えて、ファイル名を変更した際に元ファイルの拡張子が消えてしまう問題がありましたので、元ファイルの拡張子を変更後のファイル名に追加するようにしております。
function myFunction(e) {
var itemResponse;
var fileName;
var movie;
var no = 1; // ファイルアップロード時の連番
//回答のオブジェクトを取得
var itemResponses = e.response.getItemResponses();
// お名前の回答結果を取得する
itemResponse = itemResponses[0];
fileName = itemResponse.getResponse() + '_' + dateToStr24HPad0(new Date(), 'YYYYMMDDhhmmss');
// ファイルの回答結果を取得する
itemResponse = itemResponses[1];
itemResponse.getResponse().forEach(function( uploadFile ) {
movie = DriveApp.getFileById(uploadFile);
var ext = getExt(movie.getName());
movie.setName(fileName + '_' + no + '.' + ext);
no++;
});
}
// フォーマットする自作関数
function dateToStr24HPad0(date, format) {
if (!format) {
// デフォルト値
format = 'YYYY/MM/DD hh:mm:ss'
}
// フォーマット文字列内のキーワードを日付に置換する
format = format.replace(/YYYY/g, date.getFullYear());
format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
return format;
}
// 拡張子を取得
function getExt(filename) {
return filename.match(/[^.]+$/);
}
プログラム解説
複数のファイルがアップロードされた場合、ファイルの回答結果を取得する処理(itemResponse = itemResponses[1];
)にてファイルIDの配列が取得できます。
あとはforEach文でファイル数だけリネームすれば対応可能です。
ディスカッション
コメント一覧
こちらのやり方を参考に、Formのアップロード画像を任意のファイル名に変更することができました。ありがとうございます!
画像ファイルが1設問に対して1枚の場合はうまくいったのですが、複数選択したときにうまく動作しません。複数の場合の対応は可能でしょうか。
ご教示いただければ幸いです。
コメントいただきありがとうございます。
こちらの記事を執筆した際には、1設問1ファイルの想定で作っており、複数ファイルが選択できることを失念しておりました。
コメントでご返答するには少々複雑となりますので複数ファイルの対応を記事に追記させていただきました。
ご参考になれば幸いです。
たくみん様
記事が一年前という事もあり、わずかな期待を込めてコメント差し上げておりました。
まさかこんなに早くご対応頂けるとは思っておらず感激しています。ありがとうございます。
追記を参考にさせていただき、手元でも無事に複数のファイル名が変更できました!
まだまだ初心者ですので私の知識では思いもつかない内容でした。少しずつ勉強していきたいと思います。
私の会社(の隣部署)では、Formのいち回答につき画像アップロードは10か所以上(×複数枚)かつ2,000回答以上あるにも関わらず、そのファイル名を手動で打ち換えるという殺人的作業を行っていましたので、泣いて喜ばれるレベルだと思います。
他方、同Form内で、ラジオボタンの質問に対して特定の回答があった場合、Formの内容と画像URLを自動でGメール送信するスクリプトも並行して作っておりました。
教えていただいたコードを参考にそちらも頑張ります!
お役に立てて光栄です。
並行して作成されているスクリプトも頑張ってください。
画像URLの取得はgetFileById()でファイル取得後、getUrl()で取得可能かと存じます。
movie = DriveApp.getFileById(uploadFile);
movie.getUrl();
Gメールの送信に関しては同ブログ内の
【Google Apps Script (GAS)】メールを送信する方法
もしくは、現在製作を進めております、同ブログのGoogle Apps Scriptのみを抜き出したこちらのブログでも解説しておりますのでご参考になればと思います。
【Google Apps Script (GAS)】Scriptからメールを送信する方法と全9オプションの設定方法を解説!
たくみん様
蛇足として書いたことにまで丁寧な解説を下さりありがとうございます。
同じく参考にいたします。
この度はどうもありがとうございました。
今後もいろいろと勉強させていただきます。
たくみん様
先日こちらで相談させて頂いた者です。
ご教示頂いた後トライ&エラーを繰り返し、
①Formのアップロード画像(複数)のファイル名を変更
②特定の回答があった場合、Formの内容と画像URLを自動でGメール送信する
ともに概ね動作するようになりました。その節はありがとうございました。
しかしそこで新たな問題が発生し「ここに書いて良いものか。。。」と思いつつコメントしております。
このFormは、指定した箇所の危険/安全を点検して報告する物なのですが
危険な場合のみ「危険」を選択し、次の設問で画像をアップロード
という事を繰り返す仕様になっています。
よって「安全」を選んだ場合、次のitemResponses[n]には画像がアップロードされず
TypeError: itemResponse.getResponse(…).forEach is not a function
のエラーが吐き出されてしまいます。
前半で画像アップロード無しですと、以後全てのファイルのファイル名が変わりません。
指定したitemResponses[n]に画像がアップロードされなかった場合
スキップして次の処理、という事になるように思いますが行き詰ってしまいました。
またお力をお貸し頂く事は可能でしょうか。
画像がアップロードされないケースがあり、その場合はスキップする処理を追加するということであっていますでしょうか?
画像がアップロードされていない場合は、回答(itemResponse)がundefinedとなるのでエラーが出ているようです。
下記のように、一度アップロードファイルの回答を取得し、if文で判定してあげるとスキップできます。
(期待した回答であれば幸いです。)
itemResponse = itemResponses[n];
if (itemResponse) {
itemResponse.getResponse().forEach(function( uploadFile ) {
/* リネーム処理 */
});
}
}
「安全/危険」の選択と「画像のアップロード」が1セットで繰り返されているということでしたら、少し複雑となります。
例えば「安全/危険」の選択と「画像のアップロード」のセットが3セットあるとして、2つ目の「画像アップロード」に対して画像をアップロードしない場合、itemResponsesの配列に入ってこないためitemResponses[n]がずれます。
(次の3セット目の画像が想定ではitemResponses[5]で取得できると思いますが、実際はitemResponses[4]で取得など)
なので、全ての回答をチェックし、ファイルアップロードの回答であることを確認後、ファイル名をリネームするようにしてみました。
記事にはしていないので少々見づらいかと存じますが、お試しください。
お試しの際はif (question == ‘ファイル’)の’ファイル’を実際に使用している設問名に変更していただきますようお願いいたします。
設問名にいくつかの種類がある場合はif (question == ‘ファイル1’ || question == ‘ファイル2’)のようにつなぐことで複数判定ができます。
for (var i = 0; i < itemResponses.length; i++) { // ファイルの回答結果を取得する itemResponse = itemResponses[i]; if (itemResponse) { var question = itemResponse.getItem().getTitle(); if (question == 'ファイル') { /* リネーム処理 */ } } }
たくみんさま
折角投稿いただいていたのに間が空いてしまい申し訳ございません。
仕事に忙殺されておりました。。。
アドバイスを参考にいくつか試行錯誤して、希望通りの動作にすることができました。
if (question == ‘ファイル1’ || question == ‘ファイル2’)
のところは、一度試して動作する事を確認できたのですが、設問の数が結構多いので、事前に配列ckStrを宣言してその中にキーワードをまとめていれておき、
if (ckStr.indexOf(question)!=-1){
としてみたところ少し短くできました(初心者ゆえ、これが正しいのかわからないのですが、、、)
今回勉強させていただいた事で仕事の効率はかなり上がると思います。 色々とお教え頂き本当にありがとうございました!