透過Python Flask網站程式上傳影像檔到Google Drive雲端硬碟(三)

上一篇文章的Python程式透過MediaFileUpload()建立上傳檔案物件。本文將修改《使用Python Flask建置影像圖檔上傳網站服務(五)》的Flask網站程式,原程式是將用戶透過網頁表單上傳的檔案存入網站伺服器的uploads資料夾,這個版本改成把檔案暫存在主記憶體,再交由MediaIoBaseUpload()建立上傳檔物件,轉傳到Google雲端硬碟。

MediaFileUpload(0與MediaIoBaseUpload()

MediaFileUpload(媒體檔案上傳)類別物件的參數

MediaFileUpload()其實有4個參數(參閱此Google API說明文件),它們的名稱和意義如下:

  • filename:檔名,字串格式的上傳檔路徑和檔名。
  • mimetype(MIME類型):上傳檔的MIME類型字串,如果沒有填寫,則依「副檔名」自動判斷。
  • chunksize:區塊大小,僅resumable(可續傳)參數設為True才有效,指定切割檔案、分批上傳的位元組(整數)大小。Google雲端程式的「請求」訊息大小上限為5MB,所以區塊大小不可大於5MB,預設為1024×1024位元組(1MB)。此參數設成-1代表不分割(不建議)。
  • resumable:可續傳,設成True代表可在斷線、重新連線之後續傳檔案。
MediaFileUpload的參數

使用io.BytesIO()建立緩存記憶體物件

Python的標準函式庫內建一個名叫io(代表「輸出∕入介面」)的模組,其中的BytesIO提供了在記憶體中讀寫位元組資料的功能,例如,把二進位檔案資料(如:圖檔)暫存在記憶體。

延續《使用Python Flask建置影像圖檔上傳網站服務(五)》貼文的Flask程式,上傳檔案的資料存在file物件,底下的敘述將建立一個BytesIO物件,然後在其中存入上傳檔案。程式碼的開頭必須先引用io模組:

io.BytesIO()與

Flask網站應用程式的src原始檔資料夾,也要存入Google的服務帳戶金鑰。

Flask網站應用程式的檔案架構

透過MediaIoBaseUpload物件上傳緩存記憶體內容到Google雲端硬碟

完整的上傳檔案到Google雲端硬碟的Python Flask主程式碼如下,這個程式也支援把ESP32-CAM拍攝的影像上傳到的Google雲端硬碟,ESP32-CAM的程式碼不變,請參閱《ESP32-CAM開發板(三):拍照並上傳影像到網站伺服器》貼文。

import datetime
import filetype
from flask import Flask, flash, request, redirect, url_for, render_template
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseUpload
import io  # 內含BytesIO類別

UPLOAD_FOLDER = '你的上傳檔資料夾的ID '
SCOPES = ['https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = 'google_auth.json'     # 金鑰檔案
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'     # 請自行修改密鑰
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 3 * 1024 * 1024

# 驗證憑證
creds = service_account.Credentials.from_service_account_file(
    SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('drive', 'v3', credentials=creds)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/', methods=['POST'])
def upload_file():
    res = handle_file(request)

    if res['msg'] == 'ok':
        flash('影像上傳完畢!')
        return render_template('index.html', filename=res['filename'])
    elif res['msg'] == 'type_error':
        flash('僅允許上傳png, jpg, jpeg和gif影像檔')
    elif res['msg'] == 'empty':
        flash('請選擇要上傳的影像')
    elif res['msg'] == 'no_file':
        flash('沒有上傳檔案')

    return redirect(url_for('index'))  # 令瀏覽器跳回首頁

@app.route('/esp32cam', methods=['POST']) # 供ESP32-CAM上傳影像的路由
def esp32cam():
    res = handle_file(request)
    return res['msg']

def handle_file(request):
    if 'filename' not in request.files:
        return {"msg": 'no_file'}

    file = request.files['filename']  # 取得上傳檔

    if file.filename == '':
        return {"msg": 'empty'}       # 傳回代表"空白"的訊息

    if file:
        file_type = filetype.guess_extension(file)  # 判斷上傳檔的類型
        MIME = file.content_type

        if file_type in ALLOWED_EXTENSIONS:
            file.stream.seek(0)
            # 重新設定檔名
            filename = str(datetime.datetime.now()).replace(
                ':', '_') + '.' + file_type

            buffer = io.BytesIO()  # 宣告記憶體物件
            file.save(buffer)  # 把檔案存入緩存記憶體

            print("上傳到Google Drive...")
            media = MediaIoBaseUpload(buffer, mimetype=MIME,
                                      chunksize=1024*1024, resumable=True)
            body = {'name': filename, 'parents': [UPLOAD_FOLDER]}

            file_id = service.files().create(
                body=body, media_body=media).execute()

            print('雲端檔名: ' + str(body['name']))
            print('雲端檔案ID:' + str(file_id['id']))

            # return {"msg": 'ok', "filename": filename}
            # 改成傳遞Google雲端檔案的ID給HTML樣板
            return {"msg": 'ok', "filename": str(file_id['id'])}
        else:
            return {"msg": 'type_error'}  # 傳回代表「檔案類型錯誤」的訊息

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

顯示上傳到Google雲端硬碟的影像檔

Flask程式上傳圖檔之後,網頁將會呈現剛剛上傳的影像,原本的HTML樣板檔(templates/index.html)是讀取伺服器的static/uploads路徑的上傳影像,要改成讀取Google雲端硬碟的上傳檔,其中的filename變數值是Flask傳入的Google雲端檔案ID

HTML樣板程式碼

完整的Python Flask上傳影像到Google雲端硬碟的程式原始碼請按此連結下載

Posts created 470

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top