每天開新文件、貼內容、調標題、再分享給同事——做久了真的會崩潰。其實這些重複動作,完全可以交給 Google Apps Script。
用 DocumentApp.create() 先一鍵生出文件,再把段落、表格、連結通通自動寫進去,最後取得 URL 丟回試算表或寄信通知,流程一次走完。
這篇會用白話範例帶你從零開始:建立文件、設定樣式、搬到指定資料夾、設定權限,到「大量產生多份報告」的做法與避坑清單。不需要高深背景,只要會開 Apps Script,就能把原本半小時的例行事,縮成一個按鈕。把腦力留給分析,雜事交給程式。希望本篇文章可以幫助到需要的您。
目錄
{tocify} $title={目錄}
為什麼要用程式來開新文件?
如果你每天都要把資料、報表或範本輸出成多份 Google 文件(Google Docs),手動「新增 → 命名 → 貼內容 → 排版 → 分享」會很耗時。Google Apps Script(GAS) 提供的 DocumentApp 服務,讓你用一行程式就能建立全新的文件,再把段落、表格、連結統統塞進去,甚至自動命名與分享。核心入口就是這個方法:
const doc = DocumentApp.create('你的文件標題');
這行會回傳一個 Document 物件,代表剛建立的那份 Google 文件,接著你就能對它做各種操作(例如 getBody().appendParagraph()、saveAndClose())。這些行為都出現在官方參考與教學示例中,可以視為標準做法。
快速上手:從零寫到可用的最小範例
範例一:最短程式碼,產生一份空白文件並加一段文字
function createSimpleDoc() {
const doc = DocumentApp.create('我的第一份自動化文件'); // 建立文件
doc.getBody().appendParagraph('這份文件由 Apps Script 自動建立。'); // 加一段話
doc.saveAndClose(); // 儲存並關閉
Logger.log('文件網址:%s', doc.getUrl());
}
DocumentApp.create(name):建立並開啟一份新文件,回傳 Document。
getBody().appendParagraph():往文件主體追加段落。
saveAndClose():把變更寫回並關閉文件(大量寫入時更穩定)。
註:官方示例中常見的教學,就是先 create(),再 getBody().appendParagraph(),最後取 getUrl() 給使用者。
DocumentApp.create() 到底做了什麼?
1. 在你的 Google 雲端硬碟建立一份新文件,並回傳對應的 Document 物件。
2. 這份文件預設會建立在你的雲端硬碟根目錄(My Drive),稍後你可以用 DriveApp 把它移到指定資料夾(後面會示範)。
3. 回傳物件可直接操作:寫文字、表格、分頁、圖片、設定標題等,再用 saveAndClose() 收尾。
新手常見疑問
要不要一定 saveAndClose()?
腳本結束時系統會自動處理,但大量寫入或長迴圈情境,建議你手動分段 saveAndClose(),避免觸發「變更太多、請先儲存」的錯誤。
可否直接建立在指定資料夾?
DocumentApp.create() 只能建在根目錄,建立後再用 DriveApp 移動是通用解。社群與官方討論也都是採用「先建後移」的流程。
建立後怎麼馬上把網址給使用者?
doc.getUrl() 就是連結,寫回試算表或發通知信都可行(官方 Quickstart 就是這樣示範)。
實戰操作:從建立、寫入、移動、分享到存取
步驟 1:建立與命名
const doc = DocumentApp.create('每月營運報表_2025-10');
建立完成即回傳 Document 物件,可立刻操作。
步驟 2:寫入段落、標題、表格
const body = doc.getBody();
body.appendParagraph('一、總覽').setHeading(DocumentApp.ParagraphHeading.HEADING1);
body.appendParagraph('以下為本月重點指標與摘要說明。');
const table = body.appendTable([
['指標', '數值', 'MoM', 'YoY'],
['營收', 'NT$ 12,300,000', '+5.3%', '+12.1%'],
['新客數', '1,284', '+2.1%', '+9.7%'],
]);
table.getRow(0).editAsText().setBold(true);
body.appendParagraph('二、細項分析').setHeading(DocumentApp.ParagraphHeading.HEADING1);
Paragraph、Table 等元素用法可查 Document/Body/Table 參考。
步驟 3:儲存與關閉(建議)
doc.saveAndClose();
可避免「一次寫入過多變更」的例外,特別是巨量生成文件或在迴圈中寫入。
步驟 4:把文件移到指定資料夾
const file = DriveApp.getFileById(doc.getId());
const target = DriveApp.getFolderById('你的資料夾ID');
target.addFile(file); // 加到目標資料夾
DriveApp.getRootFolder().removeFile(file); // 從根目錄移除(等於搬移)
這是實務上最穩的「先建後移」流程;社群長年以此為準。
步驟 5:設定檔名與分享權限(選用)
doc.setName('【內部】每月營運報表_2025-10'); // 改名
file.addEditor('teammate@example.com'); // 加編輯者
file.addViewer('boss@example.com'); // 加檢視者
setName() 與分享 API 在 Document/Drive 參考中皆有記載。
進階情境:從資料自動產出一批文件(批次生文)
以下情境:你有一張試算表,每列是「一個部門」的 KPI,要自動為每個部門各產出一份報告。流程:讀資料 → 逐列 create() → 寫內容 → 存網址回表 → 移動到資料夾。
function batchCreateDeptReports() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('KPI');
const rows = sh.getDataRange().getValues();
const folder = DriveApp.getFolderById('你的資料夾ID');
const header = rows.shift(); // 去標題列
const [deptCol, revenueCol, newUserCol] = [0, 1, 2]; // 假設欄位
rows.forEach((r, i) => {
const dept = r[deptCol];
const revenue = r[revenueCol];
const newUsers = r[newUserCol];
const doc = DocumentApp.create(`部門月報_${dept}`);
const body = doc.getBody();
body.appendParagraph(`${dept} 部門月報`).setHeading(DocumentApp.ParagraphHeading.TITLE);
body.appendParagraph(`本月營收:${revenue}`);
body.appendParagraph(`本月新客:${newUsers}`);
// 加表格
body.appendTable([
['KPI', '數值'],
['營收', `${revenue}`],
['新客', `${newUsers}`],
]);
doc.saveAndClose();
// 移動檔案
const file = DriveApp.getFileById(doc.getId());
folder.addFile(file);
DriveApp.getRootFolder().removeFile(file);
// 把連結寫回試算表第 5 欄
sh.getRange(i + 2, 5).setValue(doc.getUrl());
});
}
此模式等同於多數官方/社群文章推薦的流程:create() → getBody() 寫入 → saveAndClose() → getUrl() → 移動/分享。
模板實務:用既有範本 + 取代文字
雖然本文主軸是 create(),但很多人會搭配「模板複製」來得到更漂亮的排版。你可以:
1. 先 DriveApp.getFileById(templateId).makeCopy(newName) 建出文件,
2. 再 DocumentApp.openById(newId) 取代 { {placeholder} }。
這與 create() 互補,兩者都屬官方與社群的主流做法。
權限、授權與觸發器注意事項
授權 Scope:
常見寫入操作會需要 https://www.googleapis.com/auth/documents(或 documents.currentonly)等權限,首次執行會跳授權。官方 Body/Document 參考都有標示。
觸發器:
若把程式掛在 時間觸發器 或 表單提交觸發器 上跑,初次或修改後都可能重新要求授權。
自訂函數限制:
在 Google 試算表的 自訂函數 內,嚴格限制對檔案系統的寫入與網路請求,直接 create() 可能報權限或限制錯誤;建議用按鈕觸發的一般函數或觸發器來跑。社群討論與官方教學也多採這類結構。
預設建立位置與「搬移」最佳實務
如前所述,create() 一律建在 My Drive 根目錄。要落在特定資料夾,建議用:
const file = DriveApp.getFileById(doc.getId());
target.addFile(file);
DriveApp.getRootFolder().removeFile(file);
這個「先加入目標、再從根移除」的流程,已在多篇社群問答裡被反覆確認。
大量寫入、效能與穩定度
分批 saveAndClose():
若你在單一文件內做超大量的 appendParagraph/appendTable,可能碰到「變更過多」錯誤。建議分段存檔再 openById() 繼續。
減少操作次數:
能一次組成陣列建立表格就不要逐格寫(官方 Table 參考也建議在大量資料時用陣列)。
I/O 分離:
先把試算表資料整批讀到陣列,再迴圈處理(避免一格一格 getValue())。這是 Apps Script 社群長期的性能建議。
常見問題與雷點
1. TypeError: Cannot read properties of undefined (reading 'saveAndClose')
代表 doc 不是你想的那個物件(可能作用域或回傳值搞丟),或你在模板複製後忘了用 DocumentApp.openById(newId) 取得 Document。
2. Too many changes applied before saving document
一次改太多,請分批 saveAndClose() 再 openById() 接續處理。
3. Cannot find method saveAndClose(string)
saveAndClose() 沒有參數,若你不小心傳了字串,GAS 會說「找不到這個方法」。
4. 在試算表自訂函數中 create() 報錯或無效
自訂函數環境有沙箱限制,不適合做檔案建立;請改用一般函數 + 觸發器。
5. 移動到資料夾失敗
確認你先 addFile() 再 removeFile(),且腳本擁有 Drive 權限。相關討論與解法請參考社群串。
互動功能加值:目錄、頁首頁尾、連結
create() 只是開門,精彩都在後面。官方參考中,你可以:
設定標題層級與段落樣式(Heading、粗體、斜體)。
建立表格、列表、分頁。
建立連結或把文字轉為可點擊的 URL(實務部落格也有大量範例)。
小提醒:Google 文件不能以表格作為最後一個元素,官方 Body 參考說明在表格後會自動補一個空白段落,屬正常行為。
完整範例:從 Sheets 一鍵產生多份「部門報告」並寄信通知
這段把官方 Quickstart 的精神擴充:建立 → 寫內容 → 存連結 → 寄通知信。
function createDocsAndNotify() {
const sh = SpreadsheetApp.getActive().getSheetByName('KPI');
const rows = sh.getDataRange().getValues();
const folder = DriveApp.getFolderById('你的資料夾ID');
const emails = ['boss@example.com', 'ops@example.com'];
rows.slice(1).forEach(r => {
const [dept, revenue, newUsers] = r;
const doc = DocumentApp.create(`【月報】${dept}`);
const body = doc.getBody();
body.appendParagraph(`${dept} 月報`).setHeading(DocumentApp.ParagraphHeading.TITLE);
body.appendParagraph(`營收:${revenue}`);
body.appendParagraph(`新客:${newUsers}`);
body.appendTable([
['KPI', '值'],
['營收', revenue],
['新客', newUsers],
]);
doc.saveAndClose();
const file = DriveApp.getFileById(doc.getId());
folder.addFile(file);
DriveApp.getRootFolder().removeFile(file);
// 通知:把文件連結寄給相關人員
const url = doc.getUrl();
GmailApp.sendEmail(
emails.join(','),
`已產生 ${dept} 月報`,
`文件連結:${url}\n\n此信由 Apps Script 自動發送。`
);
});
}
測試與除錯建議
1. 先做小型資料測試(3~5 筆),觀察格式與權限是否正確。
2. Logger 與 Execution log:把 doc.getId()、doc.getUrl() 打出來,有助於定位錯誤。
3. 分段儲存:迴圈大量生成時每 N 份就 Utilities.sleep(200) + 獨立 saveAndClose(),降低配額與變更壓力。
4. 權限先跑通:第一次執行要手動授權,之後再掛觸發器。
問題集
1. 可以直接建立在共用雲端硬碟嗎?
create() 仍是建在個人根目錄;要放到共用雲端硬碟,請在該雲端硬碟下先取得目標資料夾,再用「先加後移」方式。
2. 可以一次建立很多份嗎?
可以,但要注意 Apps Script 的執行時間與服務配額。建議分批處理並分段 saveAndClose()。
3. 文件最後一行為什麼多一個空白段落?
Google 文件不能以表格結尾,官方文件說表格後會自動補段落。
4. Tabs(文件分頁物件)能用嗎?
近年的文件 API 引入「Tabs」概念(取得分頁、設定使用者的作用分頁等),但與 create() 核心任務無衝突。日常產出報表,多半不用動到。細節以官方參考為準。
