Google 雲端硬碟:用 Apps Script 玩轉 google 雲端硬碟

 


雲端硬碟越用越亂,不是因為你不勤勞,而是因為沒有一致的規則。

DriveApp 讓規則落地:一段小小的 Apps Script,就能自動幫你建立「年/月/專案」的資料夾結構、把超過 N 天沒更新的檔案移到封存區,甚至一口氣把分享權限調整好。

本篇文章盡量說明內容,逐一介紹 DriveApp 的核心類別與常用方法,並用可直接貼上去跑的範例,帶你把例行公事自動化。中間會提醒你權限與配額的眉角,哪些操作會被限流、為什麼建議用 ID 不用名稱。目標很單純:讓你的雲端硬碟「可預測、可維護、可交接」。希望本篇文章能夠幫助到需要的您。


目錄

{tocify} $title={目錄} 


為什麼要用 DriveApp?

        如果你在公司/個人工作流裡大量使用 Google Drive,總有一些重複到發慌的任務:自動建資料夾、批次搬檔、命名規則、上傳與轉檔、設定分享、找出符合條件的檔案、同步報表…這些都可以交給 Google Apps Script(GAS) 的內建 DriveApp 服務處理。

        DriveApp 是直接內建在 GAS 裡的高階封裝,語法友好,幾行程式就能把 Drive 例行事務自動化。官方定義很直接:它讓腳本可以在 Google Drive 裡「建立、搜尋、修改」檔案與資料夾;若你需要最新功能或管理「共享雲端硬碟(Shared drives)」細節,則建議改用進階 Drive 服務(Advanced Drive)或 Drive API。


內建 DriveApp vs. Advanced Drive(Drive API)

DriveApp(內建服務):

        寫起來最省腦;CRUD 檔案/資料夾、設定分享、走遍階層都很順手。不過在一些新功能與共享雲端硬碟支援上有侷限。

Advanced Drive Service:

        把 Google Drive API 直接搬到 GAS,用法更完整、能控的欄位更多(版本、修訂、客製屬性…)。缺點是需要先在專案中啟用,語法也更貼近 REST。官方現在同時支援 v2/v3(可在進階服務選版本)。


什麼時候要上 Advanced?

當你需要查修訂版本、玩自訂檔案屬性、或對共享雲端硬碟做更細緻的查詢清單(像 drives.list)、甚至跨網域權限細節,這些就交給 Advanced。


DriveApp 世界觀:你會用到的核心 Class

以下把最常用、而且你八成會遇到的類別與枚舉(enums)整理出來,每個都附一點操作節奏:

DriveApp:

        服務進入點;像 getFileById(id), getFolderById(id), createFile(blob|name, content), createFolder(name), searchFiles(query) 等等。

File:

        單一檔案實例;可 getName() / setName() / moveTo(folder) / setSharing(access, permission) / getBlob() …。

Folder:

        資料夾實例;可 createFile() / createFolder() / getFiles() / getFolders()…。

FileIterator / FolderIterator:

        大量結果的迭代器,用 hasNext() + next() 慢慢吐出來。這種迭代器要用 while (it.hasNext()) 的寫法。

Access(列舉):

        分享對象層級,像 PRIVATE, ANYONE_WITH_LINK, DOMAIN…;要搭配 setSharing()。

Permission(列舉):

        分享權限層級,像 VIEW, EDIT…;注意部分型別不能用於某些檔案,誤用會丟例外。


常用操作範例

走遍你雲端硬碟裡所有檔案,列出名稱

function listAllFiles() {
  const it = DriveApp.getFiles();
  while (it.hasNext()) {
    const file = it.next();
    console.log(file.getName());
  }
}


這就是官網示範的典型用法:拿到 FileIterator,while 迭代輸出。


建立專案資料夾 + 上傳文字檔

function bootstrapProjectFolder() {
  const root = DriveApp.getRootFolder();
  const project = root.createFolder('2025_行銷活動');
  const file = project.createFile('README.txt', '這是活動專案的說明檔。');
  console.log(project.getUrl(), file.getUrl());
}


依條件搜尋檔案(標題關鍵字 + MIME 型態)

function findSlides() {
  // 以 query 語法過濾(與 Drive 進階搜尋相似)
  const q = "title contains '簡報' and mimeType = 'application/vnd.google-apps.presentation'";
  const it = DriveApp.searchFiles(q);
  const hits = [];
  while (it.hasNext()) hits.push(it.next().getName());
  console.log(hits);
}


searchFiles(query) 用的是 Drive 的查詢語法子集;複雜情境(例如跨共享雲端硬碟的搜尋、或需要更多欄位)時,建議切到 Advanced Drive。


設定分享(任何知道連結的人可檢視)

function shareByLink(fileId) {
  const file = DriveApp.getFileById(fileId);
  file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
}


Access 與 Permission 兩個列舉是搭配 setSharing() 的標準寫法。某些 Permission 值(或某些檔案型別)不支援會直接丟例外。


批次搬家:把某資料夾底下的檔案全移到新資料夾

function moveAllFiles(srcFolderId, dstFolderId) {
  const src = DriveApp.getFolderById(srcFolderId);
  const dst = DriveApp.getFolderById(dstFolderId);
  const files = src.getFiles();
  while (files.hasNext()) {
    const f = files.next();
    f.moveTo(dst);
  }
}


下載檔案內容(Blob)與版本化命名

function exportFileContent(fileId) {
  const file = DriveApp.getFileById(fileId);
  const blob = file.getBlob();
  const ts = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyyMMdd_HHmmss");
  DriveApp.getRootFolder().createFile(`backup_${file.getName()}_${ts}.bin`, blob.getDataAsString());
}


在資料夾裡再生資料夾(樹狀結構)

function scaffoldFolders() {
  const root = DriveApp.getRootFolder().createFolder('2025_課程');
  const weeks = ['W1','W2','W3','W4','W5'];
  weeks.forEach(w => root.createFolder(w));
}


權限模型:你在改誰的東西?

Drive 的分享其實分兩層:可被誰看(Access) + 能做什麼(Permission)。

        Access 決定對象:「私有」、「同網域」、「任何知道連結」…

        Permission 決定權限:「檢視」、「評論」、「編輯」等。

        在 Apps Script 中用 file.setSharing(DriveApp.Access.X, DriveApp.Permission.Y) 一次搞定;但要注意並不是所有型態都能用所有 Permission 值,誤用會噴例外,這是文件寫死的限制。

        共享雲端硬碟注意事項:DriveApp 可以處理不少基本事,但若你要列出共享雲端硬碟、或在那裡做更進階的條件查詢,官方建議用 Advanced Drive(可呼叫 v3 的 drives.list 等端點)。


迭代器思維:為什麼多用 while (hasNext())?

FileIterator / FolderIterator 是「一個一個吐」的設計,避免一次載回上千筆造成記憶體壓力。標準用法是 while (it.hasNext()) { const f = it.next(); ... }。想用 map/filter 的陣列花招?可以,但得自己先裝進陣列。


與配額(Quota)和平共處

Apps Script 所有服務都有配額:包含每日、每分鐘、執行時間上限等。超標就丟例外、腳本直接停。Drive 相關操作也算在這些額度裡。上線前請壓測、加上退避機制(exponential backoff)、必要時分批排程。官方配額頁面會定期更新,務必以那裡為準。


錯誤處理與健全性設計

盡量用 ID,不要靠名稱:名稱不保證唯一,getFileById() / getFolderById() 才穩。

檢查存在性:searchFiles() 可能回空;getFiles()/getFolders() 也可能 0 筆。

分批與休息:大量迭代時每 N 筆 Utilities.sleep(200),避開瞬間爆量。

權限先規劃:組織內建議以「同網域 + 可檢視」作為預設,再針對內部協作人員升到 EDIT。

錯誤可恢復:包 try/catch,把失敗的 fileId 收集起來重試;不可恢復就記 Log + 寄通知。


常見雷點(踩過就不想再踩第二次)

1. 用名稱抓檔案 → 碰上同名就悲劇,改用 ID。

2. 一次載回太多 → 乖乖用 Iterator + while (hasNext()),分批處理。

3. 亂設分享 → Access 與 Permission 搭配不當會丟例外;先用小樣本驗證。

4. 忽略配額 → 沒有 backoff、沒有分批,腳本在高峰期就倒。

5. 共享雲端硬碟當作一般 My Drive 玩 → 高階需求請用 Advanced Drive / Drive API。


專案歸檔機器人

目標:每晚把「進行中」資料夾裡,30 天內無更新的檔案搬到 Archive/,並設定「知道連結可檢視」。

重點:分批、保守權限、可重入(多跑幾次結果一樣)。


const CONFIG = {
  SRC_FOLDER_ID: 'xxxxx',  // 進行中
  ARC_FOLDER_ID: 'yyyyy',  // Archive
  INACTIVITY_DAYS: 30
};

function nightlyArchive() {
  const src = DriveApp.getFolderById(CONFIG.SRC_FOLDER_ID);
  const dst = DriveApp.getFolderById(CONFIG.ARC_FOLDER_ID);
  const cutoff = Date.now() - CONFIG.INACTIVITY_DAYS * 24 * 3600 * 1000;

  const it = src.getFiles();
  let processed = 0, moved = 0;
  while (it.hasNext()) {
    const f = it.next();
    processed++;
    try {
      const lastUpdated = f.getLastUpdated().getTime();
      if (lastUpdated < cutoff) {
        f.moveTo(dst);
        f.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW); // 視需求調整
        moved++;
      }
    } catch (e) {
      console.error(`Fail on ${f.getId()}: ${e}`);
    }
    if (processed % 50 === 0) Utilities.sleep(300); // 和緩呼叫,配額友善
  }
  console.log({ processed, moved });
}


Iterator 搭配批次 sleep,避免一口氣觸發速率限制。

權限用最小可行值,後續再提升(或改用組織網域權限)。



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