如何使用 Python Flask 将文件从 Google App Engine 上传到 Google Cloud Storage?

How to upload file from Google App Engine to Google Cloud Storage using Python Flask?

我想将文件从 Google App Engine 上传到 Google Cloud Storage 我正在使用 Pyhton 3.8 和 Flask。

app.yaml:

runtime: python38

requirements.txt

Flask==2.0.0;
google-cloud
google-cloud-storage

我尝试使用 Flask 上传文件 (https://www.tutorialspoint.com/flask/flask_file_uploading.htm) to /tmp (in App Engine temporary storage (https://cloud.google.com/appengine/docs/standard/python3/using-temp-files))

然后我尝试使用以下代码示例从临时存储上传到 Google 云存储:(https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-code-sample)

但这给了我这个错误:

OSError: [Errno 30] Read-only file system: 'file.xlsx'

我也从这个示例中尝试过:(https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/appengine/standard/storage/api-client/main.py) 并给我同样的错误。

然后我尝试使用 gsutil (https://cloud.google.com/storage/docs/uploading-objects#gsutil) using subprocess.check_output (Return value of x = os.system(..)) 仍然给我同样的错误。

谁能帮帮我?我该怎么办?

############################################# ####

已解决

############################################# ####

谢谢你Edo Akse,我的错误是使用“/tmp”而不是“/tmp/”,非常感谢你帮助我。

以下是有效的完整代码。

from flask import Flask, request
from werkzeug.utils import secure_filename
from google.cloud import storage
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = "/tmp/"

@app.route('/')
def index():
    page = '''
    <form action="/upload" method="post" enctype="multipart/form-data">
        <input name="file" class="custom-file-input" type="file">
        <button type="submit" class="btn btn-success">Submit</button>
    </form>
    '''
    return page

@app.route('/upload',methods=["POST"])
def upload():
    try:
        if request.method == 'POST':
            f = request.files['file']
            f.save(os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename)))
            
            #Start Do Main Process Here
            TMP_FILE_NAME = os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename))
            BUCKET_NAME = 'fsample123'
            result = upload_blob(BUCKET_NAME, TMP_FILE_NAME, f"tmp/{secure_filename(f.filename)}")
            #End Do Main Process Here
            return result
            
    except Exception as e:
        return str(e)

def upload_blob(bucket_name, source_file_name, destination_blob_name):
    """Uploads a file to the bucket."""
    # SOURCE:
    # https://cloud.google.com/storage/docs/uploading-objects#uploading-an-object

    # The ID of your GCS bucket
    # bucket_name = "your-bucket-name"
    # The path to your file to upload
    # source_file_name = "local/path/to/file"
    # The ID of your GCS object
    # destination_blob_name = "storage-object-name"

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(destination_blob_name)
    blob.upload_from_filename(source_file_name)
    return "File {} uploaded to {}.".format(source_file_name, destination_blob_name)

if __name__ == '__main__':
   app.run()

所以问题不在于上传到 GCS,而在于您创建的临时文件。

The only directory that has write access/tmp 并注意它不在 GAE 实例之间共享,并且在实例重新启动时消失...

from google.cloud import storage


def upload_blob(bucket_name, source_file_name, destination_blob_name):
    """Uploads a file to the bucket."""
    # SOURCE:
    # https://cloud.google.com/storage/docs/uploading-objects#uploading-an-object

    # The ID of your GCS bucket
    # bucket_name = "your-bucket-name"
    # The path to your file to upload
    # source_file_name = "local/path/to/file"
    # The ID of your GCS object
    # destination_blob_name = "storage-object-name"

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(destination_blob_name)
    blob.upload_from_filename(source_file_name)
    print(
        "File {} uploaded to {}.".format(
            source_file_name, destination_blob_name
        )
    )


TMP_PATH = "/tmp/"
TMP_FILE_NAME = f"{TMP_PATH}file.xlsx"
BUCKET_NAME = '<your-bucket-name>'


with open(TMP_FILE_NAME, "w") as outfile:
    outfile.write("write file action goes here")
upload_blob(BUCKET_NAME, TMP_FILE_NAME, "Target file path goes here...")