D9 - 如何用 Google Apps Script 自动化对 Google Drive 的操作?(一)列出所有档案 ID 与相关资讯

来到了第九天。但一样先讲结论,如果你很急着用,可以直接使用这份 Add-On: Drive Explorer,功能还蛮强大的!自己写的好处是,如果你想结合其他功能会比较方便。对於想知道怎麽做的人,让我们开始吧!

今天的目标

现在几乎每天都会打开 Google Drive,但有时当档案一多,就会面临两个问题——权限设置不清,当一个人加入或离职时,要重复好几次开开关关。又或是要将不同的线上文件寄信并分享给不同人,这些都会需要知道档案 ID。有没有一个快速的方式,可以让我们抓出特定资料夹内的档案 ID,并用一个表格管理权限呢?

  1. 要怎麽列出 Google Drive 中的档案 ID 们?
  2. 要怎麽取得 Google Drive 中的档案们的权限?
  3. 要怎麽设定 Google Drive 中的档案们的权限给不同人?

这次的主题我们会分成两天写。第一题会在今天跟大家分享,明天会针对第二题与第三题。那我们就开始吧!


Q1. 要怎麽列出 Google Drive 中的档案 ID 们?

Step 1 开启 Google Sheet,并串起 GAS

因为我们要用到 Google Sheet ,所以一样用其作为开启的管道。借用一下 D8 的影片,来说明怎麽样开启一个有连结 GAS 的 Google Sheet。

一样执行时会有「需要验证」出现,让我借用一下 D2 的影片。

Step 2 确认要抓的 Google Drive 位置,并将其 ID 记录到 GAS 上

这边我们开一个资料夹,并且在里面设置一些档案,其中有一些是有子目录的。要注意里面有个「demo」资料夹

那这边要特别提一下「ID」的概念,每一个 Google 产品都有特定的 ID,位置可以参考这张图

这边提供两种取得方式——

一种是直接从网址上复制,另一种是按右键时会出现的。这边用影片解释。好,那当我们取得要抓的档案 ID 後,就是将其丢到 GAS 上,一样开一个 environment.gs 存放资料。这边示范完整的流程——

Step 3 读单一资料夹内的档案、名称与ID

在 Google Drive 官方定义的 API 中,主要会将能操作的物件分成三种,分别是 FolderFileUser。会用不同的 API 读取。

我们来拆解步骤——

  1. 透过 getFolderById() 读取 Folder
  2. 读到资料夹後,再接着用 getFiles() 会读出 files (实际上是 fileIterator,但可以理解成「很多档案」就是)。
  3. 这个 filesfileIterator)会将这个资料夹内的档案一个个列出来,这边我列出它的档名(getName())和 ID(getId())。

完整程序码在这——

function readFiles(){
  let folder = DriveApp.getFolderById(drive_ID);
  let files = folder.getFiles();
  let file_arr = []
  while (files.hasNext()) {
    let file = files.next();
    file_arr.push([file.getName(),file.getId()]);
  };
  Logger.log(file_arr);
}

跑起来长这样——

好那你会发现一个问题,是这边并没有列出「资料夹」。仔细一看会发现我们里面并没有我们在 Step 2 埋梗的「资料夹」 demo ,那请问我们要如何抓到 demo 与里面的小资料夹(还有资料)?

Step 4 打开子目录内的目录

Step 3 我们是用 getFiles(),这边我们就带大家来看看 getFolders() 怎麽样读取。

这边我们要用到的技巧叫做 DP (Dynamic Programming),简单来说就是(1)在根目录(或目标位置)执行 DP,去发现子目录,而(2)进到每个子目录後,一旦发现还有子子目录,就会再执行一次 DP,并且不断重复到找到全部的位置为止。

程序码长这样,是直接借用 rpm 在 Stakeholder 的回应:Google apps script - iterate folder and subfolder,觉得写得很好懂。其中的 getSubFolders(parent) 中还有 getSubFolders(child)的写法,就是所谓的 DP。

function getSubFolders(parent) {
  parent = parent.getId();
  let childFolder = DriveApp.getFolderById(parent).getFolders();
  while(childFolder.hasNext()) {
    let child = childFolder.next();
    Logger.log(child.getName());
    getSubFolders(child);
  }
  return;
}

function listFolders() {
  let parentFolder = DriveApp.getFolderById(drive_ID);
  let childFolders = parentFolder.getFolders();
  while(childFolders.hasNext()) {
    let child = childFolders.next();
    Logger.log(child.getName());
    getSubFolders(child);
  }
}

好,那执行起来会长什麽样子呢?(可以参考 Step 2 的架构图)——

但这样只有列出「目录」,又要怎麽样列出所有档案,包括子目录内的档案呢?让我们从 Step 5 来看看。

Step 5 列出所有档案,包括子目录内的档案们

这边就要结合我们的 Step 3 和 Step 4 啦。我们先将 Step 3 改写成会读取输入的 Folder Object 的 function。

function readFilesInFolder(folder){
  let files = folder.getFiles();
  while (files.hasNext()) {
    let file = files.next();
    Logger.log([file.getName(),file.getId()]);
  };
}

接着,在将上面这段放入 Step 4 中。

function getSubFolders(parent) {
  parent = parent.getId();
  let childFolder = DriveApp.getFolderById(parent).getFolders();
  while(childFolder.hasNext()) {
    let child = childFolder.next();
    Logger.log(child.getName());
    readFilesInFolder(child)
    getSubFolders(child);
  }
  return;
}

function listFolders() {
  let parentFolder = DriveApp.getFolderById(drive_ID);
  readFilesInFolder(parentFolder)
  let childFolders = parentFolder.getFolders();
  while(childFolders.hasNext()) {
    let child = childFolders.next();
    Logger.log(child.getName());
    readFilesInFolder(child);
    getSubFolders(child);
  }
}

那接着我们执行看看——

补充的是,有人问说如果是在一进去 Google Drive 的根目录(没有 ID 的部分),要怎麽读?其实就是直接 getFiles() 就行了。这边是修改 官方范例的程序码 供大家参考。

function readAllFiles(){
    // Log the name of every file in the user's Drive.
    let files = DriveApp.getFiles();
    while (files.hasNext()) {
      let file = files.next();
      Logger.log(file.getName());
    }
}

一样按执行就好罗!好,那今天学了...

  1. 档案 ID 与获取方式
  2. 档案列出方式
  3. 资料夹列出方式
  4. 结合档案与资料夹的列出方式

接着可以将结果参考 D8 写入 Google Sheet。好,那今天就是我们的 D9,明天 D10 会继续介绍结合读取档案後的操作模式。如果还有问题,透过留言之外,也可以到 Facebook Group,想开很久这次铁人赛才真的开起来哈哈哈,欢迎来当 Founding Member。如果不想错过可以订阅按赞小铃铛(?),也欢迎留言跟我说你还想知道什麽做法/主题。我们明天见。


<<:  Day1-前言

>>:  鬼故事 - 我不晓得这东西为甚麽会动

< 关於 React: 开始打地基| 父组件、子组件、兄弟姐妹组件的关系 >

09-14-2021 本章内容 子组件更新父组件的状态 设定组建间的状态 设定组建间事件处理的程序 ...

DAY8 Linebot 自动回应-1

设定完成後,开启Django应用程序(APP)的views.py档案,这边就是撰写LINE Bot接...

Day20 订单金流 -- 基础结构

从一开始的api流程到後面购物车以及订单, 今天我们终於又要将快要忘掉的金流给提起拉!! 首先让我们...

【Day 16】for 回圈

在写程序时,我们可能需要重复执行某些程序,总不可能每行程序一直复制贴上,这时候就会用到我们的回圈(l...

[Day30] 让自己过得爽,才是好主管

曾有一位与我合作的一线主管问过我一个问题:「我一直在学习观察,试着找出团队系统有没有问题,但我总觉得...