【GAS】スプレッドシートをカンマ区切りのテキストファイル(拡張子 txt)としてダウンロードする方法を実例で解説|csvからtxtに変換する方法

Apps Script apps script GAS-prograshi(プロぐらし)-kv AppsScript
記事内に広告が含まれていることがあります。

Amazonなどのサイトによっては商品を入稿するときにCSVではなく、カンマ区切りのtxt形式でアップロードしなければいけない場合があります。

そんなときに、CSVファイルをカンマ区切りのテキストファイル(拡張子 txt)に変換する方法について、スプレッドシート上にダウンロードボタンを表示して、ボタンクリックでカンマ区切りのtxtファイルとしてダウンロードする方法について実例で解説しています。


参考: GoogleドライブのファイルをCSV→TXTに変換する方法

なお、ダウンロードボタンではなく、Googleドライブにあるcsvファイルをtxtに変換する方法は下記をご参考ください。

【GAS】CSVをカンマ区切りのテキストファイル(拡張子 txt)に変換する方法を実例で解説|Googleドライブ上のファイルを変換する



CSVファイルをテキストファイルに変換する方法

そもそもですが、CSVファイルをテキストファイルに変換するには、実は拡張子を「.csv」から「.txt」に変換するだけで対応できます。

例えば「APPダウンロード項目.csv」というファイルがあるとします。


これを開くと以下のようになります。


このファイルの拡張子を「.txt」に変更するとテキストファイルになります。


つまり、通常のカンマ区切りのCSVファイルを作成して、そのファイル名の拡張子を「.csv」から「.txt」に変更すればカンマ区切りのCSVファイルになります。

ダウンロードボタンを使ってカンマ区切りのテキストファイルを取得するときもこの方法を使うことができます。


ボタンダウンロード機能の概要

ここで紹介するスプレッドシートをカンマ区切りのテキストファイル(拡張子 txt)としてダウンロードする方法は、以下のようにスプレッドシート上にサイドバーメニューとしてダウンロードボタンを表示します。

スプレッドシート上に「プログラム」というメニューを追加して、その中の「ファイルダウンロード」をクリックします。


すると、「ダウロード」というサイドバーが表示され、「CSV」と「TXT」というボタンを表示します。


「CSV」をクリックすればCSVファイルを、「TXT」をクリックすればTXTファイルをダウンロードします。



「.txt」ファイルをダブルクリックで開くとカンマ区切りのtxtファイルになっています。



ファイルとコード

作成するのは以下の2つのファイルです。

作成するファイル
  1. メニューバー.gs
  2. index.html



それぞれのファイルのコードは以下になります。

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  const menu = ui.createMenu('プログラム');
  menu.addItem('ファイルダウンロード', 'sidebarDownload');
  menu.addToUi();
}


function sidebarDownload() {
  const html = HtmlService.createHtmlOutputFromFile("index").setTitle("ダウンロードボタン");
  SpreadsheetApp.getUi().showSidebar(html);
}

function createDataUrl(type) {
  const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL };
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  let url = null;
  if (type == "csv" || type == "txt") {
    url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
  }
  if (url) {
    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();
    return {
      url: url,
      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),
      filename: `${sheet.getSheetName()}.${type}`,
    };
  }
  return { data: null, filename: null };
}


<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      input {
        border-radius: 50%;
        line-height: 100px;
        width: 100px;
        height: 100px;
        padding: 0 5px 0;
        margin: 15px;
        background: #f0e0e0;
        -webkit-box-shadow: 0 5px 0 #f0e0e0;
        box-shadow: 0 5px 0 #f0e0e0;
      }

      input:hover {
        -webkit-transform: translate(0, 3px);
        transform: translate(0, 3px);
        -webkit-box-shadow: 0 2px 0 #f0e0e0;
        box-shadow: 0 2px 0 #f0e0e0;
      }
    </style>
  </head>
  <body>
    <h1 align="center">ダウンロード</h1>
    <div align="center">
      <input type="button" value="CSV" onclick="download('csv')" /><br>
      <input type="button" value="TXT" onclick="download('txt')" />
    </div>
  </body>

  <script>
    function download(type) {
      google.script.run
        .withSuccessHandler(({ data, filename }) => {
          if (data && filename) {
            const a = document.createElement("a");
            document.body.appendChild(a);
            a.download = filename;
            a.href = data;         
            a.click();
          }
        })
        .createDataUrl(type);
    }
  </script>

</html>



サイドバーの作成方法

スプレッドシートにサイドバーを表示する方法はここでは割愛します。詳細は下記をご参考ください。


作成したときに、AppScriptとHTMLファイルの中身をそれぞれ上記のファイルにしてください。


ダウンロード処理の流れ

サイドバーでHTMLファイルを表示する

続いて実際のダウンロード処理の流れについて解説します。

スプレッドシート上で「ファイルダウンロード」というメニューをクリックすると「sidebarDownload」という関数を実行します。

function sidebarDownload() {
  const html = HtmlService.createHtmlOutputFromFile("index").setTitle("ダウンロードボタン");
  SpreadsheetApp.getUi().showSidebar(html);
}


これでサイドバーに指定したHTMLファイルの内容を表示します。


onclickイベント

ボタンをクリックするとHTMLファイルで割り当てられているonclickイベントが発動します。

  <input type="button" value="CSV" onclick="download('csv')" /><br>
  <input type="button" value="TXT" onclick="download('txt')" />


inputの属性の1つに「onclick」を設定することで、このタグに対してonclickのイベントハンドラを設置することができます。

実行する関数名と渡す引数を指定します。

onclick="実行する関数名(引数)"


例えば、以下のような記述があるとします。

  <input type="button" value="CSV" onclick="download('csv')" />

この場合、CSVと書かれたinputボタンをクリックすると、downloadという関数を実行し、その関数にcsvという文字列を引数として渡します。



scriptタグ、download関数

HTML内にscriptタグを使って実行するdownload関数の処理を記述します。

  <script>
    function download(type) {
      google.script.run
        .withSuccessHandler(({ data, filename }) => {
          if (data && filename) {
            const a = document.createElement("a");
            document.body.appendChild(a);
            a.download = filename;
            a.href = data;
            a.click();
          }
        })
        .createDataUrl(type);
    }
  </script>


function download(type)とすることで、渡された引数の値をtypeという変数に格納します。

CSVボタンがクリックされた場合はtype="csv"、TXTボタンがクリックされた場合はtype="txt"となります。

ここの処理は結構肝なので、下の方に切り出して詳細を解説します。


createDataUrl関数

download関数の処理の中で「createDataUrl関数」も実行しています。

.createDataUrl(type);


これは、AppScriptに記述してある関数です。

function createDataUrl(type) {
  const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL };
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  let url = null;
  if (type == "csv" || type == "txt") {
    url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
  }
  if (url) {
    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();
    return {
      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),
      filename: `${sheet.getSheetName()}.${type}`,
    };
  }
  return { data: null, filename: null };
}

この処理を実行することで、スプレッドシートをCSVに変換してダウンロードするためのリンクを生成します。

戻り値の部分は以下になります。

    return {
      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),
      filename: `${sheet.getSheetName()}.${type}`,
    };

オブジェクト形式でdataプロパティの値にダウンロード用のURL、filemameプロパティの値にシート名.typeというファイル名を指定しています。


この戻り値がgoogle.script.run.withSuccessHandlerに渡されます。

        .withSuccessHandler(({ data, filename }) => {
          if (data && filename) {
            const a = document.createElement("a");
            document.body.appendChild(a);
            a.download = filename;
            a.href = data;
            a.click();
          }
        })

aタグにファイルダウンロードの名前としてdownload=filenameという属性を追加し、ダウンロードリンクとしてhref=dataという属性を追加しています。

最後に、clickイベントを使って自動ダウンロードを行います。


scriptタグの中身

今回の処理で肝となるscriptタグの中身についてもう少し詳しく解説していきます。

  <script>
    function download(type) {
      google.script.run
        .withSuccessHandler(({ data, filename }) => {
          if (data && filename) {
            const a = document.createElement("a");
            document.body.appendChild(a);
            a.download = filename;
            a.href = data;
            a.click();
          }
        })
        .createDataUrl(type);
    }
  </script>



google.script.runとは何か?

onlickイベントで作動する処理の一番最初にgoogle.script.runがあります。

これはAppScriptで作成したHTMLファイルの中でAppScriptを実行できるとても便利な処理です。


App Scriptではファイルの種類として「スクリプト」と「HTML」を作成することができます。


このHTMLファイルの中で使う処理になります。


(参考)クラス google.script.run(クライアントサイド API)



withSuccessHandler

withSuccessHandlerはgoogle.script.runクラスの中で使えるメソッドです。

以下のように使用します。

google.script.run.withSuccessHandler(関数).先に実行する関数

withSuccessHandlerを使うと、後ろに指定したサーバーサイド関数が正常に返された場合に実行するコールバック関数を設定することができます。

簡単に言うと、先に用意されている関数がエラーなく実行されたら次にこの処理を行うということです。


今回使用しているコードをざっくりまとめると以下になります。

      google.script.run
        .withSuccessHandler(処理)
        .createDataUrl(type);

つまり、先にcreateDataUrl(type)を実行し、その結果を受けてwithSuccessHandlerの処理を行うという処理になります。


(参考)クラス google.script.run: withSuccessHandler



createDataUrl(type)|CSVとPDFダウンロード用のURLを作成する

コード全体像

withSuccessHandlerで指定した関数を実行する前に実行しているのがcreateDataUrl(type)です。

  <script>
    function download(type) {
      google.script.run
        .withSuccessHandler()
        .createDataUrl(type);
    }
  </script>



download関数で渡された引数を渡しています。

この関数はappscriptの方に記載されています。この処理でCSVとPDFダウンロード用のURLを作成します。

function createDataUrl(type) {
  const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL, pdf: MimeType.PDF };
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  let url = null;

  if (type == "csv" || type == "txt") {
    url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
  }
  if (url) {
    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();
    return {
      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),
      filename: `${sheet.getSheetName()}.${type}`,
    };
  }
  return { data: null, filename: null };
}



CSVダウンロードURLの作成

スプレッドシートのURLを作成

url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;


まず、スプレッドシートをCSVとしてダウンロードするためのURLを生成してます。

https://docs.google.com/spreadsheets/d/${ss.getId()}

スプレッドシートのオブジェクトに対してgetIdを使用することでシートのID番号を取得しています。



gvizライブラリを使用|gvizとは何か?

/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;

続いて「gviz」という表記を入れています。これは「Google Visualization API」というAPIを使用するという指示です。

後ろのtq?以降でどのように使用するかを指定しています。

tqx=out:csv&gid=${sheet.getSheetId()}`;

上記のようにtqxを使用して「out:csv」を指定するとCSVファイルをダウンロードすることができます。



Base64への変換(エンコード)

Base64とは何か?

上記で作成したダウンロード用のURLをクリックするだけでもダウンロードできます。

ですが、ここではより汎用性を持たせるためにダウンロードファイルをbase64にエンコードして、base64の状態でダウンロードリンクを作成しています。

function createDataUrl(type) {
  const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL, pdf: MimeType.PDF };
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  let url = null;

  if (type == "csv") {
    url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
  } else if (type == "pdf") {
    url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}`;
  }
  if (url) {
    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();
    return {
      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),
      filename: `${sheet.getSheetName()}.${type}`,
    };
  }
  return { data: null, filename: null };
}


base64とは何か?

base64とは、64進数でのデータ表記です。

すべてのデータをアルファベット(a~z, A~Z)と数字(0~9)、記号(+, ー)の64文字でエンコードします。

base64はすべてのデータを英数字で表すMIME(Multipurpose Internet Mail Extensions)という企画の中で定められたデータ変換方法です。

base64を使うことで特殊文字を英数字に変換したり、画像や音声データを英数字に変換することができます。

つまり、PDFファイルや画像、音声などをbase64でエンコードし英数字に変換し、メーラーやHTMLなどでそれらをそのまま通常のデータのように扱うことができます。



base64への変換処理

ファイルをbase64に変換する処理は以下になります。

    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();
    return {
      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),
      filename: `${sheet.getSheetName()}.${type}`,
    };



Blobをbase64にエンコードする方法(解説用)

上記の処理はURLを利用してBlobファイルを取得しているため複雑に見えますが、より簡略化すると以下のようになります。

const blob = Utilities.newBlob(データ);
Utilities.base64Encode(blob.getBytes());

GASのUtilitiesクラスのnewBlobメソッドを使うことで、引数に指定したデータをBlobとして取得することができます。

このBlobデータに対してgetBytesメソッドを使うと、バイトとして取得することができます。

これを、Utilitesクラスのbase64Encodeメソッドを使ってbase64にエンコードします。

Blobとは何か?

GASを使っているとBlobをよく使います。Blobとは何か?については下記をご参考ください。

【GAS】Blobとは何か?実例で解説|Utilities.newBlobやMIMEタイプの指定方法



ダウンロードURLから取得したファイルをBlobファイルに変換する

今回の場合はGoogleドライブなどに保存されたファイルを直接blobファイルとして取得するのではなく、ダウンロードURLから取得したファイルをBlobファイルに変換します。

    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();


UrlFetchApp

UrlFetchAppクラスを使うと、インターネット経由でリソースを取得することができます。他のWEBサイト上のデータを取得するなどスクレイピングで使われることが多いです。


(参考)Class UrlFetchApp


fetch

fetchメソッドはUrlFetchAppクラスで使えるメソッドです。

fetch(url, パラメーター)

第1引数でアクセスしたいURLを指定し、第2引数に付与したいパラメータを指定します。第2引数は省略可能です。

パラメータは以下のようにオブジェクト形式で記述します。

{
  'method' : 'post',
  'contentType': 'application/json',
  'payload' : JSON.stringify(data)
}



今回の場合は以下のように headersを指定しています。

UrlFetchApp.fetch(url, {headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` }})

「Authorization」を使って認証処理をおこないたいのでヘッダーリクエストに認証情報を渡しています。


なお、headersなどのパラメータはJavaScriptのfetchメソッドに準拠しています。


(参考)


OAuth 2.0のアクセス トークンを取得

OAuth2.0とはAPIにトークンを使ってアクセスする認証方式のことです。

headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` }

パラメーターとして「headers」にOAuth2.0認証用のアクセストークンを渡しています。

「Bearer(ベアラー)」とは認証方法の1つでBearer認証と呼ばれ、OAuth 2.0の仕様の一部として定義されています。

ScriptApp.getOAuthToken()で、ScriptAppクラスのgetOAuthTokenメソッドを実行しOAuth2.0認証用のアクセストークンを取得しています。


(参考)getOAuthToken()


ここまでの処理でようやくダウンロードリンクを叩いて、ファイルにアクセスすることができます。



blobファイルとして取得する|getBlob

    const blob = UrlFetchApp.fetch(url, {
      headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    }).getBlob();

最後にダウンロードリンクを叩いて得られたファイルをgetblobメソッドを使ってBlobとして取得しています。


base64のダウンロードリンクの作成

      data:
        `data:${mimeTypes[type]};base64,` +
        Utilities.base64Encode(blob.getBytes()),


base64へのエンコード

Utilities.base64Encode(blob.getBytes())

Blobオブジェクトに変換したファイルをUtilitiesクラスのbase64encodeメソッドを使ってbase64にエンコードします。

base64にエンコードする際はgetBytesメソッドを使ってBlobオブジェクトをバイトデータにエンコードする必要があります。


base64ダウンロードリンクの作成

data:${mimeTypes[type]};base64,` + Utilities.base64Encode(blob.getBytes()),


base64ダウンロードURLの作成は以下のような構造になります。

data:[<mediatype>][;base64],<data>

冒頭を「data:」としてMIMEタイプ、「;bae64」、カンマで区切ってbase64形式のデータを記述します。

MIMEタイプは今回はCSVファイルの場合はExcel「MICROSOFT_EXCEL」、PDFの場合は「PDF」を指定しています。


MIMEタイプとは何か?

MIMEタイプはGASでも非常によく使うものです。詳細については下記をご参考ください。

【GAS】MIMEタイプとは何か?AppScriptで使えるmimeTYPEの一覧を実例で解説


なお、ダウンロードURLのdata:データURLと呼ばれ、小さなファイルをインラインで埋め込むためのスキームです。

(参考)Mmdn: データURL


以上でbase64形式のダウンロードURLの作成が完了です。


ファイル名の指定

createDataUrl関数の最後の処理としてファイル名を指定します。

filename: `${sheet.getSheetName()}.${type}`


やっていることはとても簡単です。sheet.getSheetName()で現在のシートの名前を取得しています。

そこに、引数で渡された値を拡張子としてつけています。

ここの.${type}がポイントです。ダウンロードURLはCSVファイルですが、TXTボタンをクリックすると変数typeに「txt」が渡されるので、ファイル名の拡張子が「.txt」となります。

これで、CSVファイルをカンマ区切りのテキストファイルとして命名することができます。



ボタンクリックでファイルをダウンロードする処理

AppScriptを使って、ファイルダウンロード用のURLとファイル名の生成ができたので、最後にボタンクリックでファイルをダウンロードする処理を記述します。

これが、index.htmlの中のwithSuccessHandlerメソッドで指定した処理になります。

      google.script.run
        .withSuccessHandler(({ data, filename }) => {
          if (data && filename) {
            const a = document.createElement("a");
            document.body.appendChild(a);
            a.download = filename;
            a.href = data;
            a.click();
          }
        })


document.createElement

document.createElementはタグを生成するJavaScriptのメソッドです。

 document.createElement(タグ名[, オプション]);

第1引数でタグ名を文字列で指定することで、指定したタグを生成します。なお、ここで生成されたものをエレメントと呼びます。


document.createElement("a");

↓ aタグを生成します。

<a></a>


(参考)Mmdn: Document.createElement()


appendChild

親ノード.appendChild(エレメント)

appendChildは指定した親ノードの中に、指定したエレメントを挿入するメソッドです。


以下のようにすることで、bodyタグの中に先ほど作成したエレメント(aタグ)を挿入することができます。

document.body.appendChild(a)

 ↓

<body>
  <a></a>
</body>


(参考)


エレメント.属性名=値

エレメント.属性名=値

エレメントに対して「.属性名=値」とすると、指定した属性と値を追加することができます。


aタグのhref属性

aタグにhref属性を付与すると、指定したURLがリンク先となります。

const a = document.createElement("a");
document.body.appendChild(a);

a.href = data;

 ↓

<body>
  <a href="data:MIMEtype;base64,dabafgrag~"></a>
</body>






aタグのdownload属性

aタグにdownload属性を付与すると、hrefで指定したダウンロードURLをクリックしたときに、download属性の値がファイル名となります。

以下の場合aタグのエレメントにdownload属性を付与し、値は変数filenameになります。

a.download = filename;

 ↓

<body>
  <a download="シート名.csv" href="data:MIMEtype;base64,dabafgrag~"></a>
</body>


これでダウンロード用のaタグが完成します。



clickメソッド

最後に、clickメソッドを実行して、aタグをクリックしています。

a.click();


これで、指定したダウンロードURLをクリックして、ファイルを指定したファイル名でダウンロードすることができます。


(参考)Mmdn: click()


以上で完成です。

お疲れさまでした^^

タイトルとURLをコピーしました