GoogleAppsScript屋さん

GoogleAppsScript のサンプルコードなどを載せていきます

ローカルファイルを編集(アップロード・ダウンロード)

ローカルファイルを読み込むローカルにファイルダウンロード でそれぞれローカルファイルのアップロード・ダウンロードを実現したので、それらを合わせて「ローカルファイルの編集」をするサンプルコードを紹介したいと思います。

編集内容は「全角英数字を半角に変換」とします。

なお、ローカルファイルを直接編集するのではないため、アップロードファイルとダウンロードファイルは別々になることにご注意ください。

また、今回スプレッドシートで値は読み書きせず、ダイアログの土台としてのみ利用しています。

サンプルコード

以下4ファイルが登場します。

  • コード.gs
  • upload.html
  • download.html
  • upload.txt

コード.gs

var readFileData;  // アップロードしたファイルデータを保管しておくためのグローバル変数

function main() {
  var html = HtmlService.createHtmlOutputFromFile("upload");
  SpreadsheetApp.getUi().showModalDialog(html, 'ファイルアップロード');
}

function readFileAndShowDownloadDialog(formObject) {
 
  // フォームで指定したテキストファイルを読み込む
  var fileBlob = formObject.myFile;
  
  // テキストとして取得(Windowsの場合、文字コードに Shift_JIS を指定)
  var text = fileBlob.getDataAsString("sjis");  
  
  // テキストデータをグローバル変数に保管する
  readFileData = text;
  
  // ファイルダウンロード用のダイアログを表示する
  var html = HtmlService.createTemplateFromFile("download").evaluate();
  SpreadsheetApp.getUi().showModalDialog(html, 'ファイルダウンロード');
  
}


function getData() {    
  
  // 読み込んだテキストデータの全角英数字を半角に変換する
  return readFileData.replace(/[a-zA-Z0-9]/g, function(s) {
    return String.fromCharCode(s.charCodeAt(0) - 65248);
  });
  
}

upload.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
    
      // すべてのフォームをイベントリスナーに登録する
      function preventFormSubmit() {
        var forms = document.querySelectorAll('form');
        for (var i = 0; i < forms.length; i++) {
          forms[i].addEventListener('submit', function(event) {
            event.preventDefault();
          });
        }
      }
      window.addEventListener('load', preventFormSubmit);      
      
      // フォームのサブミットで呼ばれる処理
      function handleFormSubmit(formObject) {
        // GASで定義した関数を呼び出す
        google.script.run.readFileAndShowDownloadDialog(formObject);

      }
    </script>
  </head>
  <body>
    <form id="myForm" onsubmit="handleFormSubmit(this)" enctype="multipart/form-data">
      <input name="myFile" type="file" /><br>
      <button type="submit">読込</button>
    </form>
  </body>
</html>

download.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      
      // ダウンロード
      function handleDownload() {
        var content = <?= getData(); ?>;  // 出力データを GAS から取得する
        var blob = new Blob([ content ], { "type" : "text/csv"});
        document.getElementById("download").href = window.URL.createObjectURL(blob);
      }

    </script>
  </head>
  <body>
    <a id="download" href="#" download="download.txt" onclick="handleDownload()">ダウンロード</a>
  </body>
</html>

upload.txt

1234567890
0987654321
abc
cba
XYZ
ZYX

実行の流れ

当サンプルコードを実行した時の流れです。

  1. GAS側の function main() を実行するとファイルアップロード用のダイアログが表示されます。 f:id:rokuni62:20170912145907p:plain

  2. 「ファイルを選択」からアップロードするファイルを選択します。 f:id:rokuni62:20170912145918p:plain

  3. 「読込」ボタンを押してファイルを読み込みます。 f:id:rokuni62:20170912145926p:plain

  4. 次にファイルダウンロード用のダイアログが表示されます。 f:id:rokuni62:20170912145931p:plain

  5. 「ダウンロード」を押すと編集後のテキストファイルがダウンロードされます。 f:id:rokuni62:20170912145944p:plain

  6. ダウンロードされたファイルを確認すると全角英数字が半角に変換されています。 f:id:rokuni62:20170912145952p:plain

解説

アップロード・ダウンロードの解説はそれぞれ ローカルファイルを読み込むローカルにファイルダウンロード に書いてあるので省略します。

当サンプルコードで工夫した点は2つ。

  1. アップロード機能とダウンロード機能を別ファイルに分けたこと
  2. アップロードファイルのデータをグローバル変数に保管したこと

アップロード機能とダウンロード機能を別ファイルに分けた理由

最初はアップロード機能・ダウンロード機能をひとつのHTMLファイルにまとめようとしましたが、上手くいきませんでした。

その理由はダウンロード機能の var content = <?= getData(); ?>; の箇所です。

<?= ... ?> という記法は HtmlService.createTemplateFromFile("XXX").evaluate() でHTMLを生成したタイミングで固定されてしまいます。

そのためひとつのHTMLファイルに機能をまとめようとすると、「ファイルがアップロードされる前にダウンロードファイルデータが固定」されてしまい、「アップロードファイルを編集する」という目的を達成できません。

そこでアップロード機能・ダウンロード機能でそれぞれHTMLファイルを分割し、アップロードファイルを読み込んだ後にダウンロード用HTMLダイアログを生成することで「編集」を実現しました。

アップロードファイルのデータをグローバル変数に保管した理由

今回、プログラムの流れとしては以下のようになっています。

  1. アップロード用HTMLダイアログ生成(GAS)
  2. ファイルのアップロード(JavaScript
  3. アップロードされたファイルデータの読込み(GAS)
  4. ダウンロード用HTMLダイアログ生成(GAS)
  5. ダウンロードするファイルデータの展開・編集(GAS⇒JavaScript
  6. ファイルのダウンロード(JavaScript

ここで重要なのは 「5.ダウンロードするファイルデータの展開・編集(GAS⇒JavaScript)」です。

GAS は「2.ファイルのアップロード(JavaScript)」で得たファイルデータを「5.ダウンロードするファイルデータの展開・編集(GAS⇒JavaScript)」で展開まで保管しておかなければなりません。

HTML ファイルを分割したため、データの橋渡しを GAS が行う必要があるということです。

変数は必要がなければローカル定義が望ましいですが、ファイルデータを受け渡す必要があったためグローバル変数を定義することで実現しました。