Amazonで商品を見るセール会場へ

Googleドライブ│フォルダ内のファイル数を集計する方法│GAS

各フォルダの直下にあるファイル数を集計します。

親の行は子の件数を合算せず、全走査の合計は実行ログに分けて表示します。

ファイル件数は使用容量ではありません。

以下の模擬検証は2026年10月2日の記録です。

ローカルの模擬検証を行いましたが、Googleへの認可・実シートへの反映・Driveの実ファイル列挙は未検証です。

この集計はApps Scriptエディタから実行し、Webアプリの配備は不要です。

2026年10月25日に公式資料と配布ZIPを照合し、article-295.jsと本文コードの一致を確認しました。

今回はGoogle上での実行や画面確認を行っていません。

目次

練習用の入力と設定

実行するGoogleアカウントで閲覧できるフォルダと、編集できる練習用スプレッドシートを用意します。

出力先スプレッドシートを集計対象フォルダ内に置くと、それ自体もファイル数に含まれます。

ZIPを展開し、article-295.jsの内容を新規Apps Scriptプロジェクトのコードへ貼り付けて保存します。

同名の関数を含むため、別の記事のコードを同じプロジェクトへ混ぜないでください。

データ整理の練習コードとHTML例をダウンロード(ZIP)

設定名設定する値
FOLDER_ID閲覧できる練習フォルダID
SPREADSHEET_ID練習用スプレッドシートID
RECURSIVE直下だけはfalse。子フォルダも含める場合はtrue

左側の「プロジェクトの設定」を開き、「スクリプト プロパティ」に表の3項目を追加して保存します。

RECURSIVEは小文字のtrueまたはfalseを、引用符を付けずに入力してください。

掲載コードは文字列trueとの完全一致で判定するため、未設定やTRUEでは子フォルダを調べません。

コード中にあるSHEET_NAMEは、この集計で呼ばれない共通関数の設定なので入力不要です。

追加・保存の場所はGoogle公式のプロパティ設定手順を参照してください。

まず新規の練習データを使い、要求される認可範囲と操作内容を確認してください。

GASの構文から学びたい場合は、次の入門書も候補です。

このサンプルを試すために購入する必要はなく、まず本文と公式資料で動きを確かめてください。

秀和システム
¥2,860(2026/09/24 18:33時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場
スポンサーリンク

入力例と実行する関数

親フォルダに1個、子に1個の練習例では、RECURSIVE=trueの結果に親1・子1が別行で出ます。

全走査合計は2です。

最初にpreviewCountsで集計だけを行い、内容を確かめてからexportCountsで出力します。

  1. エディタでコードを保存し、関数の選択欄からpreviewCountsを選んで「実行」を押します。
  2. 初回に認可が求められたら、実行アカウントと要求されるアクセス範囲を確認します。
  3. 実行ログで、練習例のフォルダ数が2、全走査ファイル数が2になるか確かめます。
  4. エラーがなければexportCountsを選んで実行し、指定したスプレッドシートを開きます。
  5. 新しい練習結果_で始まるシートに、親と子の行がそれぞれ1件と出るか確認します。

previewCountsでは結果シートを作りませんが、対象フォルダの走査は実行します。

exportCountsは再び走査するため、その間にファイルが増減すると件数も変わります。

出力列はAがフォルダパス、BがフォルダID、Cが直下のファイル数で、個別ファイル名の一覧は出力しません。

操作の基本はエディタからの関数実行とGoogleサービスの認可を参照してください。

// このコードは記事ごとに別のApps Scriptプロジェクトへ保存します。
function required_(key) {
  const value=PropertiesService.getScriptProperties().getProperty(key);
  if (!value) throw new Error(key+'を設定してください');
  return value;
}
function safeCell_(value) {
  const s=String(value);
  return /^[=+@-]/.test(s) ? "'"+s : s;
}
function escapeHtml_(value) {
  return String(value).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
function https_(value) {
  const s=String(value).trim();
  if (!/^https:\/\/[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::443)?(?:[/?#][^\s<>"'\\]*)?$/i.test(s)) throw new Error('HTTPS URLを確認してください');
  return s;
}
function sourceSheet_() {
  const sheet=SpreadsheetApp.openById(required_('SPREADSHEET_ID')).getSheetByName(required_('SHEET_NAME'));
  if (!sheet) throw new Error('対象シートがありません');
  return sheet;
}
function walkFolder_(root,recursive) {
  const queue=[{folder:root,path:root.getName()}],seen=new Set(),rows=[],counts=[];
  let visitedFiles=0;
  for (let index=0;index<queue.length;index++) {
    if (index>=100) throw new Error('100フォルダを超えるため中止しました');
    const {folder,path}=queue[index],id=folder.getId();
    if (seen.has(id)) throw new Error('重複フォルダIDです');
    seen.add(id);
    const files=folder.getFiles();let count=0;
    while (files.hasNext()) {
      const file=files.next();
      if (++visitedFiles>1000) throw new Error('1000ファイルを超えるため中止しました');
      rows.push([safeCell_(path),safeCell_(file.getName()),file.getUrl(),file.getId()]);count++;
    }
    counts.push([safeCell_(path),id,count]);
    if (recursive) {
      const children=folder.getFolders();
      while(children.hasNext()) {
        const child=children.next();queue.push({folder:child,path:path+' / '+child.getName()});
        if(queue.length>100) throw new Error('100フォルダを超えるため中止しました');
      }
    }
  }
  return {rows,counts,total:visitedFiles};
}
function createOutput_(header,rows) {
  // 走査完了後だけ、新規の空シートへ一括出力します。
  const ss=SpreadsheetApp.openById(required_('SPREADSHEET_ID'));
  const name='練習結果_'+Utilities.getUuid().replace(/-/g,'');
  const sheet=ss.insertSheet(name);
  if(sheet.getMaxRows()<rows.length+1) sheet.insertRowsAfter(sheet.getMaxRows(),rows.length+1-sheet.getMaxRows());
  sheet.getRange(1,1,rows.length+1,header.length).setValues([header,...rows]);
  return name;
}
function recursive_(){return PropertiesService.getScriptProperties().getProperty('RECURSIVE')==='true';}
function previewCounts() {
  const result=walkFolder_(DriveApp.getFolderById(required_('FOLDER_ID')),recursive_());
  Logger.log('フォルダ数: '+result.counts.length+' / 全走査ファイル数: '+result.total);return result;
}
function exportCounts() {
  const result=previewCounts();
  return createOutput_(['フォルダパス','フォルダID','直下のファイル数'],result.counts);
}

確認結果と切り分け

条件結果
空フォルダフォルダの行を残して0を出力
子の件数各行は直下の数。ログの全走査合計と区別
上限・重複ID途中の集計を完成結果として書き込まない

Node.jsの模擬検証は5記事合計69ケースです。

純粋関数の結果と、模擬のGoogleオブジェクトで対象選択・書込先・失敗時停止を確認した範囲であり、実サービスの成功を示すものではありません。

100フォルダまたは1000ファイルを超えると、掲載コードが走査を止めます。

これはサンプル独自の上限で、Google Drive全体の保存上限ではありません。

公式のApps Script実行時間は1回6分で、この件数以内でも時間切れや認可エラーになる場合があります。

途中再開はなく、共有ドライブやショートカットのリンク先、見えないファイルを含む網羅的な棚卸しは未確認です。

出力するフォルダパスの先頭が=などの記号なら、文字列として扱うようにしています。

Driveの共有範囲は変更せず、閲覧URLを取得しても他のユーザーへ閲覧権限を与えることにはなりません。

設定不足のエラーが出たら、メッセージにあるプロパティ名の綴りと保存済みの値を確認します。

フォルダ取得や出力で権限エラーになる場合は、同じ実行アカウントで対象を開けるか確認してください。

子の行が出ないときはRECURSIVE、件数が想定と違うときはフォルダIDと出力先の置き場所を見直します。

件数上限や時間切れなら、対象を小さな子フォルダに絞って実行し直します。

件数を照合するときに残す記録

実行前に、親と子の直下にある練習ファイルを別々に数えて控えてください。

出力先シートは対象の外へ置き、集計中は練習ファイルの追加や移動を止めます。

実行日時・対象フォルダID・RECURSIVEの値・ログの件数を記録しましょう。

出力後はフォルダ名だけでなくIDも照合し、同名の別フォルダを数えていないか確認します。

親の行を子の合計と思って比較すると、正常な結果でも不足に見える点に注意してください。

一致しない場合は、直下だけの実行から始めて、子を含める条件に一つずつ広げます。

広い範囲でエラーが出たときは、上限値を増やす前に小さい対象で完了するかを確認してください。

この記録を残すと、設定の違いと走査中のファイル増減を分けて調べやすくなります。

停止と戻し方

この例は定期トリガーを作成しません。

既存トリガーから呼ぶ変更を加える場合は、まず手動で1回確認します。

定期実行を終了するときは、対象のトリガーを削除します。

結果シートは毎回新規です。

書込時の失敗で途中結果が残る場合は完成した一覧として使わず、既存の元データと混ぜないでください。

結果の削除や古いシートの一括消去はコードに含めていません。

公式資料

Driveフォルダの取得と列挙、シート範囲への反映、HTMLへの出力とエスケープ、Apps Scriptの利用上限を参照してください。

関連記事・旧実装の参考資料

従来のコードや外部の参考例は、本稿の練習ZIPと内容が異なる場合があります。

今回のコードは記事ごとに別のプロジェクトへ保存してください。

スポンサーリンク

まとめ:小さなフォルダで直下と全走査の数を照合する

まず練習用の親・子フォルダでログと各行の数を照合し、合ってから対象を広げてください。

次に学ぶ・作業環境を選ぶ

学習を続けたい方や、作業環境を整えたい方は、目的に合うガイドをご覧ください。

スプレッドシート・GASのおすすめ書籍

作業環境の作り方

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次