宮島弥山山頂から |
さて,前々回,GoogleドライブからローカルPCへ一括ダウンロードを実証しましたが,全てのダウンロードファイルをBase64エンコードで変換して,GASからHTMLに引き渡すテーブル(二次元配列files)に格納しました。
そのため,テーブル自体が大きくなりすぎ,ブラウザにおいてエラーが発生する恐れがありました。
そこで,今回はダウンロードファイル毎に,GASで「ファイル本体Data」を作成しHTMLに引き渡すように改良しました。
HTMLとGASとのやり取りは多くなりますが,GASからHTMLに渡すテーブル(二次元配列files)は小さくなり,ブラウザの容量オーバーなどの危険性は回避できると思います。
それでは学習を始めましょう。
今回のGASスクリプトのあらまし
今回作成するスクリプトの外観図は前々回とほぼ同様です。
GASダウンロード外観図 |
今回は⑧のモーダルダイアログ内で,ダウンロードファイル毎にGASから本体情報を取得するように改良しました。
シーケンスフローについて
今回のシーケンスフローは以下のとおりです。
①GASスクリプト起動(前々回と同じ)
スプレッドシートにダウンロード対象ファイルを表示するGASスクリプトを起動します。
②スプレッドシート表示(前々回と同じ)
ファイル検索ボタンを押すことで,指定フォルダからダウンロード対象ファイルを抽出してスプレッドシート上に表示します。
スプレッドシートのイメージは,以下のとおり同じです。
スプレッドシートのイメージ図 |
③ダウンロードファイル選択(前々回と同じ)
ダウンロードしたいファイルをチェックします。
④ダウンロード実行GASスクリプト起動(前々回と同じ)
ダウンロード実行ボタンを押すことで,ダウンロードファイルの存在を確認するGASスクリプトを起動します。
ダウンロード実行ボタンを押すことで,ダウンロードファイルの存在を確認するGASスクリプトを起動します。
⑤モーダルダイアログの表示(前々回と同じ)
ダウンロードするファイルがあれば,簡易ブラウザであるモーダルダイアログを表示します。
モーダルダイアログのイメージは次のとおり前々回と同じです。
モーダルダイアログ図 |
⑥ダウンロード開始(前々回と同じ)
モーダルダイアログのダウンロード開始ボタンを押下し,「google.script.run」関数
を使ってダウンロードファイル情報を収集するスクリプトを起動します。
⑦ダウンロード情報の取得(前々回と同じ)
「google.script.run」関数
のリターン値からダウンロードファイル情報群(2次配列)を取得します。
⑧ダウンロード本体の取得とダウンロードの実行(改良)および後処理(前々回に同じ)
ダウンロードファイル情報群(2次配列)から,1ファイル(各行)ずつgoogle.script.run.関数
を使ってファイル本体を読込み,HTML側のa要素を使ってローカルPCにダウンロードするよう改良します。
最後に,ダウンロード終了時にgoogle.script.run.関数
を使ってGASスクリプトを呼びだし,スプレッドシート上のダウンロードファイル指定を解除します。(前々回と同じ)
前々回と同じところは,コーディングのみ記載します。
スプレッドシートを表示するGASスクリプト
まずは,スプレッドシートを表示するGASスクリプト(①②)のコーディングです。
main.gs
function main() {
//スプレッドシートから検索するフォルダーIDと検索するMIMETYPEを読み込む
//Activeシートオブジェクト指定
var sheet = SpreadsheetApp.getActiveSheet(); //スプレッドシートクラス指定
//スプレッドシートからフォルダーIDを読み込む
var folder_id = sheet.getRange(2,3).getValue();
console.log(folder_id);
//エラーメッセージ欄をクリアする。
sheet.getRange(2,4).setValue(" ");
sheet.getRange(4,4).setValue(" ");
//フォルダーIDからフォルダーオブジェクトを取得する
var folder = getfolderobj(folder_id);
if(folder == "err"){
sheet.getRange(2,4).setValue("フォルダーIDがありません。再度実行して下さい。");
console.log("フォルダーIDがありません。"); //エラー表示
return;
}
console.log(folder.getName()); //現在のドライブ
console.log(folder.getId()); //現在のドライブ
//スプレッドシートからMIMEタイプを読み込む
var mime_type = sheet.getRange(4,3).getValue();
if (mime_type == ""){
sheet.getRange(4,4).setValue("MIMEタイプがありません。指定して下さい。");
console.log("MIMEタイプがありません。"); //エラー表示
return;
}
//MIMEタイプを配列に分解する
var mime_types = mime_type.split(/,/g);
console.log(mime_types.length);
//検索条件文字列を初期化する
var serch_cond = "";
//MIME_TYPEから検索条件文字列を編集する。
for(let i=0; i < mime_types.length; i++){
switch(mime_types[i]){
case "text/plain":
case "text/csv":
case "text/html":
case "application/pdf":
case "image/jpeg":
case "image/png":
if ( i == 0 ){
serch_cond = serch_cond + 'mimeType = "' + mime_types[i] + '"';
}
else{
serch_cond = serch_cond + ' or mimeType = "' + mime_types[i] + '"';
}
continue;
default:
sheet.getRange(4,4).setValue("指定できないMIMEタイプがあります。ご確認下さい。");
console.log("使えないMIMEタイプがあります。"); //エラー表示
return;
}
}
console.log("serch_cond=" + serch_cond);
let row_count = sheet.getLastRow() -7; //HEADER7行分を除く
let col_count = sheet.getLastColumn() -1; //利用カラムの最大数
if(row_count > 0){
//8行目から最終行までをクリア
sheet.getRange(8, 1, row_count, col_count+1).clear({contentsOnly: true, skipFilteredRows: true});
}
let row = 8;
let counter = 1;
//該当フォルダー下の該当するファイルのコレクションを取得する
const files = folder.searchFiles(serch_cond);
//console.log(files);
while (files.hasNext()){ //コレクションファイルが存在する間繰り返す
var file =files.next(); //コレクションファイルを読む
console.log(file.getName()); //ファイル名を出力する
//ファイル名,ファイルID,ファイルURLを編集する
let col = 2;
while (col < 7){ //配列の数だけ繰り返す
sheet.getRange(row,col).setBorder(true,true,true,true,true,true); //セル上下左右罫線書く
sheet.getRange(row,col).setVerticalAlignment('middle'); //セル垂直中央に設定
switch(col){
case 2: //項番を編集する
sheet.getRange(row,col).setHorizontalAlignment('center'); //セル水平中央に設定
sheet.getRange(row,col).setValue(counter);
break;
case 3: //ファイル名を編集する
sheet.getRange(row,col).setValue(file.getName());
break;
case 4: //ファイルIDを編集する
sheet.getRange(row,col).setWrap(true); //セル内折り返し設定
sheet.getRange(row,col).setValue(file.getId()); //ファイルIDを編集する
break;
case 5: //ファイルURLを編集する
sheet.getRange(row,col).setWrap(true); //セル内折り返し設定
sheet.getRange(row,col).setValue(file.getDownloadUrl()); //ファイルDWLURLを編集する
break;
case 6:
sheet.getRange(row,col).setHorizontalAlignment('center'); //セル水平中央に設定
sheet.getRange(row,col).insertCheckboxes();
}
col++;
}
row++;
counter++;
}
SpreadsheetApp.flush();
return;
}
function getfolderobj(folder_id) {
try {
return DriveApp.getFolderById(folder_id);
}
catch(e) {
return "err";
}
}
ダウンロードファイルの存在確認とモーダルダイアログの表示
次に,スプレッドシートのダウンロード実行ボタンを押下することでダウンロードファイルの存在確認とモーダルダイアログを表示します。
dwl_make.gs
function dwl_perform(){
// ダウンロードファイルの存在を確認する
var files = dwl_exist();
if(files[0][0] == ""){
Browser.msgBox("ダウンロードファイルが指定されていません");
return;
}
//htmlを起動する。
var output = HtmlService.createHtmlOutputFromFile("index");
SpreadsheetApp.getUi().showModalDialog(output, 'ダウンロードファイル指示');
}
function dwl_exist(){
//データ配列の初期化
var files = [["","","",""]];
//Activeシートオブジェクト指定
var sheet = SpreadsheetApp.getActiveSheet(); //スプレッドシートクラス指定
//ダウンロードファイルが指示されているか,確認する。
let row_count = sheet.getLastRow() -7; //HEADER7行分を除く
let col_count = sheet.getLastColumn() -1; //利用カラムの最大数
if(row_count < 1){
Browser.msgBox("ダウンロードすべきファイルがありません,再度検索実行後指示して下さい");
return;
}
//ダウンロード指示されたファイルを探す
let i = 0;
var dwl_filename = "";
var dwl_fileid = "";
var dwl_fileurl = "";
let row = 8;
//ダウンロードファイル名,ダウンロードURL,zダウンロードIDを取得する
while(row < (row_count + 8)){
if(sheet.getRange(row, 6).getValue() == true){ //ダウンロード指示有を確認
dwl_filename = sheet.getRange(row,3).getValue(); //ファイル名を退避
dwl_fileid = sheet.getRange(row,4).getValue(); //ファイルIDを退避
dwl_fileurl = sheet.getRange(row,5).getValue(); //ファイルURLを退避
files[i] = [dwl_filename, dwl_fileid, dwl_fileurl, row];
i = i + 1;
}
row = row + 1;
}
return files;
}
次に,モーダルダイアログを表示するコードを作ります。
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
#drop {
height: 50px;
border: #D4D4D4;
border-style: dashed;
border-width: 3px;
padding: 10px;
text-align: center;
}
#click {
text-align: right;
}
#result {
text-align: center;
}
</style>
</head>
<body>
<div>
<div id="drop">
<p>チェックしたファイルをダウンロードします
<button id="Dwl_button" type="button">ダウンロード開始</button>
</p>
</div>
<hr />
<div id="click">
<button id="click_1" type="button" >実行</button>
<button id="click_2" type="button" >終了</button>
</div>
<div>
<pre id="result"></pre>
</div>
</div>
</body>
</html>
ダウンロードファイル情報の取得
モーダルダイアログの「ダウンロード開始ボタン」を押下することで,ダウンロードファイル情報(二次元配列files)を取得するjavascriptを作ります。
以下のコードをindex.html内の</html>前に挿入します。
index.html
<script>
//退避エリアを初期値する
var dwl_files = [["","","",""]];
window.addEventListener('DOMContentLoaded', function() {
document.getElementById("Dwl_button").addEventListener('click', function(e){
//引数エリアを初期化する。
var files = [["","","",""]];
//ダウンロードファイルの情報を取得する
google.script.run
.withSuccessHandler(function(files){
dwl_files = files; //引数エリアを退避する。
//alert("files= " + files[0][0]);
if(files[0][0] === ""){
var msg = "日付=" + getToday() + " ダウンロードファイルはありません。";
msg = msg + "\n\n" + "終了ボタンを押して下さい。";
} else {
var msg = "日付=" + getToday() + " ファイル名=" + files[0][0];
msg = msg + "\n\n" + "ダウンロードします。実行ボタンを押して下さい";
}
document.getElementById('result').textContent = msg;
})
.withFailureHandler(function(err) { //ファイル情報取得に失敗した場合の処理
alert("ダウンロードが失敗しました。\n\nエラーメッセージ=" + err.message);
}).dwl_exist();
},true);
//*** 次の関数をココに入れる。 ***
});
function getToday(){
let today = new Date();
today.setDate(today.getDate());
const yyyy = today.getFullYear();
const mm = ("0"+(today.getMonth()+1)).slice(-2);
const dd = ("0"+today.getDate()).slice(-2);
const result = yyyy+'-'+mm+'-'+dd;
return result;
}
function spread_syuryo(){
// スプレッドシートで、アップロードUIを自動的に閉じる
google.script.host.close();
}
</script>
ダウンロード本体の取得とダウンロードの実行(改良)および後処理
基本は前々回と同じですが,ダウンロードの実行(HTML側)の繰り返し処理の中に,ダウンロードファイル本体の取得処理(GASのdwlfile_syori(files[i])関数の呼び出し)を入れています。
以下に,HTMLのjavascriptのコードを記載します。このコードは,前述の「document.getElementById("Dwl_button").addEventListener('click',
function(e)」の次の関数として設定します。
index.html
document.getElementById("click_1").addEventListener('click', async function(e){
// 退避エリアから引数を戻す
files = dwl_files;
if(files[0][0] === ""){
alert("ダウンロードファイルがありません。ダウンロード開始ボタンを押して下さい。")
return;
}
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms || 1000));
for( let i = 0; i < files.length; i++){
var msg = "日付=" + getToday() + " ファイル名=" + files[i][0];
msg = msg + "\n\n" + "ダウンロードします。実行ボタンを押して下さい";
document.getElementById('result').textContent = msg;
google.script.run
.withSuccessHandler( function(data){
let a = document.createElement("a");
document.body.appendChild(a);
a.download = files[i][0];
a.href = data;
a.click();
})
.withFailureHandler(function(err) { //ファイル情報取得に失敗した場合の処理
alert("ダウンロード終了処理が失敗しました。\n\nエラーメッセージ=" + err.message);
}).dwlfile_syori(files[i]);
var ms = 3000;
await sleep(ms);
}
google.script.run
.withSuccessHandler(function(files){
dwl_files = files; //引数エリアを退避する。
var msg = "日付=" + getToday() + " ダウンロードは終了しました。";
msg = msg + "\n\n" + "終了ボタンを押して下さい。";
document.getElementById('result').textContent = msg;
})
.withFailureHandler(function(err) { //ファイル情報取得に失敗した場合の処理
alert("ダウンロード終了処理が失敗しました。\n\nエラーメッセージ=" + err.message);
}).dwlfile_syuryo(files);
},true);
document.getElementById("click_2").addEventListener('click', function(e){
//alert("終了ボタンが押されました");
spread_syuryo()
},true);
【補足】
GASより受け取った二次元配列「files」を利用して,ファイルの繰り返し処理の中でファイル本体のデータを取得する関数「dwlfile_syori(files[i])」をgoogle.script.run関数で呼び出しています。
ファイル本体のBase64エンコードである「DataURL(data)」が正常に返された場合,「body要素にa要素を追加し,「DataURL(data)」のdownloadを行います。
その他は,前々回と同様です。
dwl_make.gs
function dwlfile_syori(file){
//ファイルIDからファイルオブジェクトを取得する
file_obj = DriveApp.getFileById(file[1]);
//ファイルブジェクトのBlobオブジェクトを取得する
blob_obj = file_obj.getBlob();
console.log(blob_obj.getBytes());
console.log(blob_obj.getContentType());
//Blobオブジュクトからバイトに変換しDataURLを編集する
var data = `data:${blob_obj.getContentType()};base64,${Utilities.base64Encode(blob_obj.getBytes())}`;
return data;
}
最後に,「google.script.run」関数で呼ばれるGASの後処理関数「dwlfile_syuryo(files)」のコードを以下に示します。
dwl_make.gs
function dwlfile_syuryo(files){
//Activeシートオブジェクト指定
var sheet = SpreadsheetApp.getActiveSheet(); //スプレッドシートクラス指定
console.log("ファイル名 = " + files[0][0]);
console.log("ファイルID = " + files[0][1]);
console.log("ファイルURL= " + files[0][2]);
console.log("row= " + files[0][3]);
console.log("ファイルDate =" + files[0][4]);
//ダウンロード処理済みのファイルがある時は,チェックを消す。
for(let i = 0; i < files.length; i++){
if(files != undefined && files[i][0] != ""){
sheet.getRange(files[i][3],6,1,1).clear({contentsOnly: true, skipFilteredRows: true});
sheet.getRange(files[i][3],7,1,1).clear({contentsOnly: true, skipFilteredRows: true});
sheet.getRange(files[i][3],6,1,1).setHorizontalAlignment('center'); //セル水平中央に設定
sheet.getRange(files[i][3],6,1,1).insertCheckboxes();
}
}
files = [["","","",""]]; //filesを初期化する。
return files;
}
【補足】
この関数では,スプレッドシート上のダウンロードファイル指定をクリアしています。
まとめ
今回は,前々回の「複数ファイルの一括ダウンロードの実証」について,ダウンロード毎にファイル本体のBase64エンコード「DataURL」を取得して行う方法を学習しました。
これで,GASとHTMLの連絡ファイルテーブル(二次元配列files)が異常に大きくならないと思います。
GASとHTMLは「google.script.run関数」で簡単に連係できるので便利ですね。
少し,長くなりましたが,以上です。
それでは,楽しいITリテラシーライフをお過ごしください。
(ご注意)情報の正確性を期していますが,実施される場合には自己責任でお願いします。
0 件のコメント:
コメントを投稿