文档

使用函数计算实现自动解压上传到OSS的ZIP文件

更新时间:
一键部署

目前对象存储不支持解压上传的ZIP的文件,您可以通过使用函数计算服务来配合实现。当匹配解压规则的ZIP文件上传到对象存储后,会自动触发函数计算进行解压。文件解压完成后,会存储至对象存储的指定目录中。

注意事项

  • 建议使用UTF-8或GB 2312编码命名您的文件或文件夹,否则可能会出现解压后的文件或文件夹名称出现乱码、解压过程中断等问题。

  • 归档或冷归档类型的文件需先解冻再解压。

  • 解压单个压缩包的最大时间是2小时,超过2小时未完成的任务会解压失败。

  • 建议ZIP包里面的单文件大小最好不超过1 GB,否则可能解压失败。

  • 建议设置函数的执行时长为2小时以上,最大可到24小时。

前提条件

操作流程

image

步骤一:创建函数

  1. 登录函数计算控制台,在左侧导航栏,单击函数

  2. 在顶部菜单栏,选择地域,然后在函数页面,单击创建函数

  3. 创建函数页面,按需选择创建函数的方式,配置以下配置项,然后单击创建

    重要配置项说明,如下所示,其余配置项的设置请参见创建函数

    • 运行环境:选择为Python 3.10

    • 函数角色:选择已有角色或创建角色,请确保函数拥有访问OSS Bucket的权限,您可以为该角色授予AliyunOSSFullAccess权限策略。

  4. 在函数详情页面,选择代码页签,在代码编辑器中编写代码,然后单击部署代码

    涉及的代码示例如下。以下示例仅为index.py代码示例,代码中需要导入的helper包和zipfile包,请参见start-unzip-oss-v3,对应的代码名称分别为helper.pyossZipfile.py

    说明

    当前示例代码支持一键部署,您可以直接在函数计算FC中一键部署本代码。start-unzip-oss-v3

    # -*- coding: utf-8 -*-
    '''
    声明:
    这个函数针对文件和文件夹命名编码是如下格式:
    1. mac/linux 系统, 默认是utf-8
    2. windows 系统, 默认是gb2312, 也可以是utf-8
    
    对于其他编码,我们这里尝试使用chardet这个库进行编码判断,但是这个并不能保证100% 正确,
    建议用户先调试函数,如果有必要再改写函数,并保证调试通过。
    
    Statement:
    This function names and encodes files and folders as follows:
    1. MAC/Linux system, default is utf-8
    2. For Windows, the default is gb2312 or utf-8
    
    For other encodings, we try to use the chardet library for coding judgment here, 
    but this is not guaranteed to be 100% correct. 
    If necessary to rewrite this function, and ensure that the debugging pass
    '''
    
    import helper
    import oss2
    import json
    import os
    import time
    import logging
    import chardet
    
    """
    When a source/ prefix object is placed in an OSS, it is hoped that the object will be decompressed and then stored in the OSS as processed/ prefixed.
    For example, source/a.zip will be processed as processed/a/... 
    "Source /", "processed/" can be changed according to the user's requirements.
    """
    # Close the info log printed by the oss SDK
    logging.getLogger("oss2.api").setLevel(logging.ERROR)
    logging.getLogger("oss2.auth").setLevel(logging.ERROR)
    
    LOGGER = logging.getLogger()
    
    # a decorator for print the excute time of a function
    
    
    def print_excute_time(func):
        def wrapper(*args, **kwargs):
            local_time = time.time()
            ret = func(*args, **kwargs)
            LOGGER.info('current Function [%s] excute time is %.2f' %
                        (func.__name__, time.time() - local_time))
            return ret
        return wrapper
    
    
    def get_zipfile_name(origin_name):  # 解决中文乱码问题
        name = origin_name
        try:
            name_bytes = origin_name.encode(encoding="cp437")
        except:
            name_bytes = origin_name.encode(encoding="utf-8")
    
        # the string to be detect is long enough, the detection result accuracy is higher
        detect = chardet.detect(name_bytes)
        confidence = detect["confidence"]
        detect_encoding = detect["encoding"]
        if confidence > 0.75 and (detect_encoding.lower() in ["gb2312", "gbk", "gb18030", "ascii", "utf-8"]):
            try:
                if detect_encoding.lower() in ["gb2312", "gbk", "gb18030"]:
                    detect_encoding = "gb18030"
                name = name_bytes.decode(detect_encoding)
            except:
                name = name_bytes.decode(encoding="gb18030")
        else:
            try:
                name = name_bytes.decode(encoding="gb18030")
            except:
                name = name_bytes.decode(encoding="utf-8")
        # fix windows \\ as dir segment
        name = name.replace("\\", "/")
        return name
    
    
    @print_excute_time
    def handler(event, context):
        """
        The object from OSS will be decompressed automatically .
        param: event:   The OSS event json string. Including oss object uri and other information.
            For detail info, please refer https://help.aliyun.com/document_detail/70140.html?spm=a2c4g.11186623.6.578.5eb8cc74AJCA9p#OSS
    
        param: context: The function context, including credential and runtime info.
    
            For detail info, please refer to https://help.aliyun.com/document_detail/56316.html#using-context
        """
        evt_lst = json.loads(event)
        creds = context.credentials
        auth = oss2.StsAuth(
            creds.access_key_id,
            creds.access_key_secret,
            creds.security_token)
    
        evt = evt_lst['events'][0]
        bucket_name = evt['oss']['bucket']['name']
        endpoint = 'oss-' + evt['region'] + '-internal.aliyuncs.com'
        bucket = oss2.Bucket(auth, endpoint, bucket_name)
        object_name = evt['oss']['object']['key']
    
        if "ObjectCreated:PutSymlink" == evt['eventName']:
            object_name = bucket.get_symlink(object_name).target_key
            if object_name == "":
                raise RuntimeError('{} is invalid symlink file'.format(
                    evt['oss']['object']['key']))
    
        file_type = os.path.splitext(object_name)[1]
    
        if file_type != ".zip":
            raise RuntimeError('{} filetype is not zip'.format(object_name))
    
        LOGGER.info("start to decompress zip file = {}".format(object_name))
    
        lst = object_name.split("/")
        zip_name = lst[-1]
        PROCESSED_DIR = os.environ.get("PROCESSED_DIR", "")
        RETAIN_FILE_NAME = os.environ.get("RETAIN_FILE_NAME", "")
        if PROCESSED_DIR and PROCESSED_DIR[-1] != "/":
            PROCESSED_DIR += "/"
        if RETAIN_FILE_NAME == "false":
            newKey = PROCESSED_DIR
        else:
            newKey = PROCESSED_DIR + zip_name
    
        zip_fp = helper.OssStreamFileLikeObject(bucket, object_name)
        newKey = newKey.replace(".zip", "/")
    
        with helper.zipfile_support_oss.ZipFile(zip_fp) as zip_file:
            for name in zip_file.namelist():
                with zip_file.open(name) as file_obj:
                    name = get_zipfile_name(name)
                    bucket.put_object(newKey + name, file_obj)

步骤二:创建OSS触发器

  1. 在函数详情页面,选择配置页签,然后在左侧导航栏,选择触发器页签。

  2. 在触发器页面,单击创建触发器,在创建触发器面板,按需设置配置项,然后单击确定

    重要配置项说明如下,其余配置项的说明请参见配置原生OSS触发器

    • 触发器类型选择对象存储OSS。

    • Bucket 名称选择已创建的存储空间名称。

    • 设置文件前缀,本文示例为src

    • 设置文件后缀,本文示例为zip

    • 选择触发事件,本文示例为oss:ObjectCreated:PutObject, oss:ObjectCreated:PostObject, oss:ObjectCreated:CompleteMultipartUpload, oss:ObjectCreated:PutSymlink

    • 角色名称:选择角色名称,请确保该角色拥有调用函数的权限,您可以为该角色授予AliyunFCFullAccess权限策略。

创建完成后,您可以在触发器页面查看已创建的OSS触发器。

步骤三:测试验证

您可以通过以下两种方式测试验证结果。

方式一:通过控制台手动上传文件验证

登录对象存储控制台,在步骤二:创建OSS触发器时选择的Bucket的src目录下上传ZIP文件,例如code.zip。上传成功后,将自动触发函数执行,解压ZIP文件并将解压后的文件转存到目标目录dst/。目标目录为自动创建,您无需手动创建。

方式二:通过配置触发器的event参数测试验证

event参数配置完成后,您需要手动单击测试函数触发函数执行,然后登录对象存储控制台,查看目标Bucket的文件列表,如果已解压目标ZIP文件,并将解压后的文件转存到目标路径dst/表示测试成功。具体操作步骤如下。

  1. 在函数详情页面,单击代码页签,然后单击测试函数右侧xialatubiao图标,从下拉列表中,选择配置测试参数

  2. 配置测试参数面板,选择事件模板,填写事件名称和event内容,然后单击确定

    event示例如下。

    {
        "events": [
            {
                "eventName": "ObjectCreated:PutObject",
                "eventSource": "acs:oss",
                "eventTime": "2023-08-13T06:45:43.000Z",
                "eventVersion": "1.0",
                "oss": {
                    "bucket": {
                        "arn": "acs:oss:cn-hangzhou:10343546824****:bucket****",
                        "name": "bucket****",
                        "ownerIdentity": "10343546824****"
                    },
                    "object": {
                        "deltaSize": 122539,
                        "eTag": "688A7BF4F233DC9C88A80BF985AB****",
                        "key": "src/test.zip",
                        "size": 122539
                    },
                    "ossSchemaVersion": "1.0",
                    "ruleId": "9adac8e253828f4f7c0466d941fa3db81161****"
                },
                "region": "cn-hangzhou",
                "requestParameters": {
                    "sourceIPAddress": "140.205.XX.XX"
                },
                "responseElements": {
                    "requestId": "58F9FF2D3DF792092E12044C"
                },
                "userIdentity": {
                    "principalId": "10343546824****"
                }
            }
        ]
    }

    event参数中不同属性字段的解释,请参见配置函数入口参数

    重要

    以上event内容仅为示例,请根据实际信息修改部分参数,同时,确保配置的Bucket中存在指定的文件(本文示例为src/test.zip文件),否则无法触发函数执行,或者函数执行会失败。

    需要根据实际情况修改的参数如下所示:

    • bucket.arn:示例如acs:oss:<region>:<your_account_id>:<your_bucket>,修改<region>为您创建函数时选择的地域,修改<your_account_id>为您的阿里云账号(主账号)ID,修改<your_bucket>为相同地域下您实际已经创建的Bucket名称。您的阿里云账号ID,可在函数计算控制台概览页面的常用信息区域获取。

    • bucket.name:修改为相同地域下您实际已经创建的Bucket名称。

    • bucket.ownerIdentity:修改为您的阿里云账号ID。

    • object.key:修改为您实际已经上传到目标Bucket下的文件。

    • region:修改为您创建函数时选择的地域。

    • userIdentity.principalId:修改为您的阿里云账号ID。

  3. 单击代码页签的测试函数进行测试。

    执行成功后,登录对象存储控制台,查看目标Bucket下目标ZIP文件(本文示例为src/test.zip)是否已被解压并保存至dst/目录。具体操作,请参见通过OSS控制台查询文件

测试完成后,如果您暂时不需要使用此应用,请及时删除应用以及关联的其他资源。

相关文档

  • 本页导读 (1)
文档反馈