2023年2月10日

gooleドライブのファイルを上書きする


 意外と面倒だったので記載しておきます。

やりたいことは「メールを受信したらその添付ファイル(画像ファイル)でドライブのファイルを上書き更新する」ことをGoogleAppsScriptで実現することです。

メールを受信してから添付ファイルを取り出すところまではいろいろなサイトで記載されているので割愛します。ここでのポイントはGメールの場合、メール単体ではなく「スレッド」単位になる点です。

まずは添付ファイルを手動でドライブに置き、それをGASからアップデートしてみます。DriveApp. には「update」が見つからなかったので「createFile」を実行してみます。

DriveApp.createFile();

作ろうとしたファイルと同じ名前のファイルがあるのだから「エラーになるだろう」と予想していたのですが、意外にもエラーになりません。ドライブを覗いてみると同名ファイルが複数存在しています。
それならばと一旦削除してからアップロードしてみました。

DriveApp.removeFile();
DriveApp.createFile();

すると見た目上はファイルが上書きされているように見えますが、Googleサイトに貼り付けた画像が更新されません。調べてみると Google Workspace 上ではファイルはファイル名ではなくファイルIDで一意になるようです。つまりこの場合はGoogleサイト上ではごみ箱に入っているファイルが表示されているわけです。

さらに調べてみると DriveApp. には「update」は存在せず、 Advanced Drive Service(DriveAPI)という仕組みを使う必要があるそうです。

DriveAPIを利用する際には、事前にGASのサービスでDriveAPIを有効化させる必要があります。「サービス」の「+」をクリックして「Drive API」をクリックし「追加」します。

コードは以下となります。

Drive.Files.update(<タイプ>,<ファイルID>,<データ>);
※今回の場合<タイプ>はいつも同じなので「{}」と省略可能。

これで同IDのファイルの新しい版としてアップロードされました。






7 件のコメント:

  1. こんにちは。私もavant様の本記事とまったく同じ事をしたいと思っておりますが、試行錯誤でうまくいきません。(監視カメラからGmailに定期送信される画像を自動受信しGドライブに自動上書き保存。それをGoogleサイトに公開。)
    本記事および、
    https://tonari-it.com/gas-gmail-attachment-drive/
    https://for-dummies.net/gas-noobs/how-to-upload-a-new-file-version-by-gas/
    このあたりを参考にし、自動受信し上書きまではできたのですが、上書きされたデータがなぜか、画像データpngからドキュメントデータ(ファイル種類はHTMLとなっており、文字列の羅列されたデータ)に変ってしまいます。拡張子はpngのままです。
    この原因がどうしても分かりませんので、何かご教示いただければ幸いです。私はこういったことの専門ではありませんが、なんとかここまでたどりついた、というレベルの人間です。どうかよろしくお願いいたします。

    返信削除
  2. コードを見ないと何とも言えないのですが、
    Drive.Files.updateの1番目の引数(TYPE)を指定していませんか?

    上書きされる側(更新前)のファイルはpngとして開けますか?
    もしpngとして開けるのならupdate時にTYPEは省略できます。

    Driveにおいては基本的に拡張子はファイル名の一部にすぎず、
    ファイルタイプと拡張子は別物です。

    返信削除
    返信
    1. ご回答くださり、本当に感謝です。
      更新前のpngは画像として開けますが、更新するとHTMLドキュメントとなってしまいます。(開けますが、文字列が表示されます)
      何せ私はほぼ素人ですので、申し訳ないです。
      ここにコードを載せて良いのか分からないのですが、以下です。

      削除
    2. const FOLDER_ID = 'abcde'; //フォルダID
      const SEARCH_TERM = 'subject:(添付ファイルテスト) ';

      function fetchFile(){

      const folder = DriveApp.getFolderById(FOLDER_ID);
      const threads = GmailApp.search(SEARCH_TERM, 0, 10);
      const messages = GmailApp.getMessagesForThreads(threads);

      for(const thread of messages){
      for(const message of thread){
      const attachments = message.getAttachments();
      for(const attachment of attachments){
      folder.createFile(attachment);
      }
      }
      }
      }
      //ファイルの新バージョンをアップロードするコード
      function updateFile() {
      let fileId = "12345"; //新バージョンアップロード対象のファイルID
      let blob = UrlFetchApp.fetch('http://drive.google.com/uc?export=view&id=12345').getBlob();
      let resource = {
      uploadType: "media",
      }
      Drive.Files.update(resource, fileId, blob);
      }

      削除
  3. お世話になっております。土日も色々と試みましたが、やはり私に基本的な知識が不足しているようです・・・。
    let blob = UrlFetchApp.fetch(
    ここの部分に問題があるのかと思いました。今ある画像を指定しているため、あたらしく取得したgmailの添付画像を指定できていない。それをどうしたらよいのか、ご教示いただけないでしょうか。可能でしたら、avant様の本件のコードをお見せいただけないでしょうか。
    よろしくお願いいたします。

    返信削除
  4. 上書きする側とされる側のファイルIDが同じなのは記述ミスだと思いますが、
    一旦blob形式で読み込んで、それからファイルタイプを指定して上書きしているんですね。

    何となく思い出してきました。
    最初、私も同じコードをネットで拾ってやってみたところ、うまくいかなかった記憶があります。
    今見ると「uploadType: "media"」って大雑把すぎるんじゃないかと思います。
    せめて「uploadType: "image/png"」だろうと。(こんなファイルタイプがあるのか知りませんが)

    私の場合、取り出したattachmentそのままを上書きするようにしました。
    ファイルタイプが変わらないからできる芸当だと思いますが。

    for(const attachment of attachments){ //メールの添付ファイルを全て調べる
    var strExt = attachment.getName().slice(-3);
    if ((strExt == 'PNG')||(strExt == 'png')){ //拡張子がpngだったら処理する
    Drive.Files.update({}, fileId,attachment);
    }
    }

    返信削除
  5. const FOLDER_ID = '19Z7socMlUf6sTLT_my_Y0VfwUx1Si53Q'; //フォルダID
    const fileId = '1BXwda8uzOsPDufV35IkHbhrQIr-LYvuX'; //フォルダID
    const SEARCH_TERM = 'subject:(添付ファイルテスト) ';

    function fetchFile(){

    const folder = DriveApp.getFolderById(FOLDER_ID);
    const threads = GmailApp.search(SEARCH_TERM, 0, 10);
    const messages = GmailApp.getMessagesForThreads(threads);

    for(const thread of messages){
    for(const message of thread){
    const attachments = message.getAttachments();
    for(const attachment of attachments){ //メールの添付ファイルを全て調べる
    var strExt = attachment.getName().slice(-3);
    if ((strExt == 'PNG')||(strExt == 'png')){ //拡張子がpngだったら処理する
    Drive.Files.update({}, fileId,attachment);
    }
    }
    }
    }
    }

    ご返信くださり、ありがとうございます。
    ご教示いただいたコードを組み込んでみたところ、上書きできるようになりました!ありがとうございます!

    あとは、また自分の問題ですが、1分おきに送られてくる監視カメラの画像を受信後すぐ削除などして、ファイルが被らないようにしないといけないのですが・・・。そこはまた頑張ってやってみたいと思います。

    本当にありがとうございます。


    返信削除