Google 雲端硬碟:取得根資料夾 getRootFolder()

 


你可能早就會用 Drive 搜尋、分享連結,但真正要把檔案「管理好」,關鍵在從根開始。DriveApp.getRootFolder() 提供一個穩定起點:我們能從這裡列目錄、過濾出需要處理的檔案、一次建立資料夾骨架,甚至定期輸出盤點報表。本文把流程拆成小模組:先授權與基本迭代,再上查詢語法、批次移動、分類歸檔,最後補上效能與配額的避坑法。你也會看見常見誤解的拆解——例如把 My Drive 與 Shared drives 混為一談,或忽略單一父層的設定,導致移動後的路徑判讀混亂。希望本篇文章內容能夠幫助到需要的您。


目錄

{tocify} $title={目錄} 


getRootFolder() 是什麼?為什麼要用它?

DriveApp.getRootFolder() 會回傳目前執行身分的「My Drive」根資料夾(回傳型別為 Folder 物件)。直白講,就是你一打開 Google Drive 網頁看到的那個最上層位置。拿到這個 Folder 物件後,你就能:

        列出根層的檔案/資料夾(例如找出「漂浮在根目錄」的零散檔案)

        建立標準化的專案資料夾結構(在根目錄下一次生成多層資料夾)

        以根目錄為起點做搜尋(searchFiles() / searchFolders())

        透過 moveTo() 把檔案從根目錄搬到指定資料夾,維持單一父層結構(亦可配合 DriveApp.enforceSingleParent(true))


官方定義:「Gets the folder at the root of the user's Drive.」且 Folder 提供查詢、移動、建立子資料夾等方法。


重要界線

getRootFolder() 只對「使用者的 My Drive」成立;若你的工作重心在 共用雲端硬碟(Shared drives),官方建議改用「進階 Drive 服務(Advanced Drive Service)」或 Drive API 直接處理,因為內建 DriveApp 在某些新功能與共用雲端硬碟存取上有侷限。


快速上手:從 0 到列出根目錄

1.     建專案與權限授權

        在 Google Drive 任何位置建立一個 Apps Script 專案(或在 Sheets/Docs 裡的擴充功能 → Apps Script)。

        貼上以下程式碼,首次執行會要求授權,因為 DriveApp 需要 Drive 權限(通常會自動偵測到 https://www.googleapis.com/auth/drive 範圍):

function listRoot() {
  const root = DriveApp.getRootFolder();
  const files = root.getFiles();
  const folders = root.getFolders();

  Logger.log('=== Files in My Drive root ===');
  while (files.hasNext()) {
    const f = files.next();
    Logger.log(`${f.getName()}  |  ${f.getUrl()}`);
  }

  Logger.log('=== Folders in My Drive root ===');
  while (folders.hasNext()) {
    const d = folders.next();
    Logger.log(`${d.getName()}  |  ${d.getUrl()}`);
  }
}


getFiles() / getFolders() 都是從 Folder 物件出發的標準迭代器用法。


2.   用搜尋語法直接篩出根層項目

你可以在根資料夾上用 Drive v2 的查詢語法(modifiedDate, title contains, starred 等)做更精準的篩選:

function searchAtRoot() {
  const root = DriveApp.getRootFolder();
  const q = 'modifiedDate > "2024-01-01" and title contains "報告"';
  const iter = root.searchFiles(q); // 或 searchFolders(q)
  while (iter.hasNext()) {
    const item = iter.next();
    Logger.log(`${item.getName()}  |  ${item.getUrl()}`);
  }
}


searchFiles() / searchFolders() 在 Folder 物件上可用,且官方文件特別提醒:內建 Drive 服務採用 Drive API v2 的查詢欄位名稱。


常見實務:清根目錄、搬動與初始化

A. 清理根目錄的零散檔案

很多人會不小心把檔案建立在根目錄,久了就很亂。以下範例會把根層所有 Google 文件(mimeType 比對)搬到你指定的「_Inbox」資料夾;如果資料夾不存在會自動建立。

function tidyRootDocs() {
  DriveApp.enforceSingleParent(true); // 強制單一父層,有助避免舊多重父層殘留
  const root = DriveApp.getRootFolder();
  const targetName = '_Inbox';

  // 找或建目標資料夾
  let target;
  const found = root.getFoldersByName(targetName);
  if (found.hasNext()) {
    target = found.next();
  } else {
    target = root.createFolder(targetName);
  }

  // 只搬 Google Docs
  const q = 'mimeType = "application/vnd.google-apps.document"';
  const files = root.searchFiles(q);
  let moved = 0;

  while (files.hasNext()) {
    const file = files.next();
    file.moveTo(target); // 直接移動,維持單一父層
    moved++;
  }

  Logger.log(`Moved ${moved} Docs to ${target.getName()}`);
}


moveTo(destination) 可把檔案/資料夾移到新父層;DriveApp.enforceSingleParent(true) 讓父層語意保持單一,對舊多父層模型有保險作用。


B. 初始化專案資料夾骨架

一次在根目錄建立多層資料夾(像 Project_X/{01_Input, 02_Work, 03_Output}):

function initProjectSkeleton(projectName) {
  const root = DriveApp.getRootFolder();
  const project = root.createFolder(projectName);
  ['01_Input', '02_Work', '03_Output'].forEach(n => project.createFolder(n));
  Logger.log(`Created ${projectName} skeleton at root.`);
}


C. 從根目錄拉一份「日誌」報表

把根層所有資料夾的名稱、建立時間、是否加星號,輸出到 Logger(你也可以寫進試算表):

function rootFolderDigest() {
  const root = DriveApp.getRootFolder();
  const folders = root.getFolders();
  while (folders.hasNext()) {
    const d = folders.next();
    Logger.log([
      d.getName(),
      d.getDateCreated(),
      d.isStarred(),
      d.getUrl()
    ].join(' | '));
  }
}


Folder 支援 getDateCreated()、isStarred()、getUrl() 等方法,足夠做目錄稽核。


Shared drives 注意事項

getRootFolder() 不會回傳共用雲端硬碟(Shared drives)的根節點;它只代表使用者個人的 My Drive。若要操作 Shared drives:

        走 進階 Drive 服務(Advanced Drive Service) 或原生 Drive API,這樣可以指定 supportsAllDrives=true、includeItemsFromAllDrives=true 等參數處理共用雲端硬碟的存取。

        官方文件也明確寫到:要存取 Shared drives,請用進階 Drive 服務以獲得最新功能與支援。


權限與授權(Scopes)

大多數 DriveApp 操作需要 https://www.googleapis.com/auth/drive 或唯讀範圍,Apps Script 會依你使用的方法自動偵測所需範圍。也可在 appsscript.json 明確設定 oauthScopes。

若你把腳本發佈成 Web App 或 附加元件(Add-on),要特別留意執行身分與授權流程。


效能與配額(Quotas)

Apps Script 各服務都有每日配額與限制;超過就會丟例外並停止。Drive 相關操作也在此列。

常見限制包含單次執行時間上限、每日總執行時間、以及各服務呼叫次數等。實務上請把批次工作拆段、加上 sleep / 分頁迭代、以及錯誤重試。


常見錯誤與雷點

以下整理在實務上最容易踩到的坑,搭配對應的思路或繞道方式:

1.「為什麼我拿不到 Shared drives 的根?」

症狀:你以為 getRootFolder() 能代表「整個雲端硬碟世界」,但它只對應 My Drive。

對策:處理 Shared drives 時,改用進階 Drive 服務 / Drive API,並帶上 Shared drives 相關參數。

2. Web App 執行 getRootFolder() 回傳異常或空值

症狀:在 Web App 內呼叫,結果拿到 null 或沒有預期的內容。

原因思路:可能是 授權範圍、執行身分(「以我執行」vs「以存取者執行」)、或網頁端 google.script.run 呼叫流程所致。

對策:

        確認 Web App 的 Deploy 設定(執行身分與存取權)

        首次執行一定要經過完整授權流程(可先在 IDE 內跑一次以觸發授權)

        若以「存取者」執行,該使用者至少要有 Drive 基本權限

        分離伺服端與用戶端邏輯:伺服端函式取得資料後再回傳純資料給前端渲染

3. 權限被網域管理員關閉

症狀:在企業網域中,明明寫法正確,卻怎麼都取不到結果。

原因:管理員若關閉 Drive SDK,會影響所有使用 Drive 服務或進階 Drive 服務的腳本、Web App、附加元件。

對策:請網域管理員檢查 Drive SDK 與允許清單(allowlist)設定。

4. 多層父目錄歷史遺留 & 移動語意不清

症狀:舊檔案在歷史上可能曾有「多重父層」;你用程式碼搬移後,仍看到怪異路徑。

對策:先呼叫 DriveApp.enforceSingleParent(true),再用 moveTo() 做移動,避免遺留多父層情況。

5. 查詢條件不生效

症狀:searchFiles()/searchFolders() 沒回傳想要的結果。

原因:DriveApp 使用 Drive v2 查詢語法,欄位名稱與 v3 有差異。

對策:對照 v2 欄位文件撰寫條件;確保是在 根資料夾物件 上呼叫。

6. 配額打滿或逾時

症狀:大量搬檔、遍歷根層時,腳本中途停止。

對策:

        拆批次(例如每 200 筆一批)

        搭配時間驅動觸發器排程

        寫入中繼點(PropertiesService)以便續跑

        加入退避(exponential backoff)與再試機制


實務範例包:從根目錄打造一條龍維運

以下整合幾個常見任務,讓你直接拿去改:

範例 1:根層「孤兒檔」搬家(依副檔名分流)

function sweepRootByExtension() {
  DriveApp.enforceSingleParent(true);
  const root = DriveApp.getRootFolder();

  // 規則表:副檔名 -> 目標資料夾
  const rules = {
    'pdf':   '_PDFs',
    'xlsx':  '_Spreadsheets',
    'csv':   '_Spreadsheets',
    'pptx':  '_Slides',
    'zip':   '_Archives'
  };

  // 先建好目標資料夾
  const ensure = name => {
    const it = root.getFoldersByName(name);
    return it.hasNext() ? it.next() : root.createFolder(name);
  };
  const targets = {};
  Object.keys(rules).forEach(ext => targets[rules[ext]] ||= ensure(rules[ext]));

  // 只看非 Google 內建類型(以檔名後綴判斷)
  const files = root.getFiles();
  let moved = 0;

  while (files.hasNext()) {
    const f = files.next();
    const name = f.getName();
    const m = name.match(/\.([A-Za-z0-9]+)$/);
    if (!m) continue;
    const ext = m[1].toLowerCase();
    const bucket = rules[ext];
    if (!bucket) continue;
    f.moveTo(targets[bucket]);
    moved++;
  }

  Logger.log(`Moved ${moved} files to categorized folders.`);
}


範例 2:根層快速稽核報表(寫回試算表)

function rootInventoryToSheet() {
  const root = DriveApp.getRootFolder();
  const ss = SpreadsheetApp.create('Root Inventory Report');
  const sh = ss.getActiveSheet();
  sh.appendRow(['Type', 'Name', 'Created', 'Starred', 'URL']);

  const pushFolder = folder => {
    sh.appendRow(['Folder', folder.getName(), folder.getDateCreated(), folder.isStarred(), folder.getUrl()]);
  };
  const pushFile = file => {
    sh.appendRow(['File', file.getName(), file.getDateCreated(), file.isStarred(), file.getUrl()]);
  };

  let it = root.getFolders();
  while (it.hasNext()) pushFolder(it.next());
  it = root.getFiles();
  while (it.hasNext()) pushFile(it.next());

  Logger.log(`Report ready: ${ss.getUrl()}`);
}


範例 3:以根為起點的條件搜尋(最近 30 天修改、名稱含關鍵字)

function searchRecentWorkAtRoot(keyword) {
  const root = DriveApp.getRootFolder();
  const since = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
  const y = since.getFullYear();
  const m = ('0' + (since.getMonth() + 1)).slice(-2);
  const d = ('0' + since.getDate()).slice(-2);
  const q = `modifiedDate > "${y}-${m}-${d}" and title contains "${keyword}"`;

  const files = root.searchFiles(q);
  const results = [];
  while (files.hasNext()) {
    const f = files.next();
    results.push([f.getName(), f.getUrl()]);
  }
  Logger.log(JSON.stringify(results, null, 2));
}


測試與除錯建議

最小步驟先通:先跑 getRootFolder() → getFiles()/getFolders(),確認授權與回傳正常,再疊加搜尋與搬移邏輯。

逐批處理:根層可能很多項目,請以迭代器逐步處理,並以 Logger 紀錄進度。

邏輯與權限分離:Web App 前端只負責顯示;資料一律由伺服端(Apps Script)取得後回傳,避免授權環節卡在前端。

管理員環境:企業網域若關了 Drive SDK,與 Drive 相關的腳本、附加元件都會受影響,要先確認這個系統性條件。


問題集

Q1. 我可不可以把 getRootFolder() 當成 Shared drives 的根?

不行。它只代表 My Drive。Shared drives 請用進階 Drive 服務或 Drive API。

Q2. 我搬檔案後,為什麼還看到舊路徑?

先啟用 DriveApp.enforceSingleParent(true) 再 moveTo(),降低多父層遺留造成的視覺錯亂。

Q3. searchFiles() 的欄位跟我印象中的不一樣?

內建 Drive 服務採 Drive v2 語法;請依 v2 欄位名稱撰寫條件。

Q4. 執行到一半停掉?

可能是配額或時間上限:把工作拆批次、加排程、做好錯誤重試,並參照官方 Quotas 文件。


張貼留言 (0)
較新的 較舊