雲端硬碟越用越亂,不是因為你不勤勞,而是因為沒有一致的規則。
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,避免一口氣觸發速率限制。
權限用最小可行值,後續再提升(或改用組織網域權限)。
