You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将多文件作为单文件分片上传至S3存储时的数据丢失问题

问题排查:S3分片上传后文件仅保留第一部分内容

我尝试将多个独立文件作为单个文件的分片上传至S3存储,最终生成的合并文件显示大小正确,但仅保留了第一个文件第一页的部分内容,其余数据均丢失。

注意:我无法先将所有文件合并为一个文件再进行分片上传

我的代码

import os
import math
import boto3

def upload_to_ovh_part_files(bucket, parts_folder):
    """
    Fonction pour uploader des fichiers en morceaux sur OVH Object Storage.
    
    :param bucket: Le nom du bucket sur OVH
    :param parts_folder: Le chemin du dossier contenant les parties à uploader
    """

    s3 = boto3.client(
        's3',
        aws_access_key_id='my_key',
        aws_secret_access_key='my-sak',
        endpoint_url='https:...',
        
    )

    parts = []
    upload_id = None

    docx_files = [f for f in os.listdir(parts_folder) if f.endswith('.docx')]
    print(f'Found {len(docx_files)} parts to upload.')

    if docx_files:
        mp = s3.create_multipart_upload(Bucket=bucket, Key='rapport_final.docx')
        upload_id = mp['UploadId']

        try:
            for i, docx_file in enumerate(docx_files, start=1):
                print(f'upload de {i} file ')
                file_path = os.path.join(parts_folder, docx_file)
                file_size = os.path.getsize(file_path)
                print(f'Uploading part {i}: {docx_file} (size: {file_size / (1024 * 1024):.2f} MB)')

                with open(file_path, 'rb') as f:
                    data = f.read()
                    part = s3.upload_part(
                        Bucket=bucket,
                        Key='rapport_final.docx',
                        PartNumber=i,
                        UploadId=upload_id,
                        Body=data
                    )
                    parts.append({
                        'ETag': part['ETag'],
                        'PartNumber': i
                    })

            s3.complete_multipart_upload(
                Bucket=bucket,
                Key='rapport_final.docx',
                UploadId=upload_id,
                MultipartUpload={'Parts': parts}
            )
            print("Upload completed successfully!")
        except Exception as e:
            print(f"Error during upload: {e}")
            if upload_id:
                s3.abort_multipart_upload(Bucket=bucket, Key='rapport_final.docx', UploadId=upload_id)
    else:
        print("No DOCX files found to upload.")

parts_folder = "rapports"
bucket_name = "mon-bucket-rapport"

upload_to_ovh_part_files(bucket_name, parts_folder)

问题原因与解决方案

核心问题

  1. 文件顺序无保证:os.listdir()返回的文件顺序由操作系统文件系统决定,并非固定的逻辑顺序。如果分片文件未按正确顺序上传,合并后的文件结构混乱,后续内容无法被docx解析。
  2. docx文件不能直接拼接:docx是结构化的ZIP压缩包,包含多个XML和资源文件。直接将多个独立docx文件作为分片拼接,会生成无效的ZIP结构——只有第一个文件的ZIP头有效,后续内容被视为无效数据,因此仅第一部分可被解析。

修正方案

  • 强制分片顺序:给分片文件命名时加入明确序号(如part_1.dat、part_2.dat),上传前对文件名排序:
    # 替换原docx_files获取逻辑,按序号排序
    docx_files = sorted([f for f in os.listdir(parts_folder) if f.endswith('.docx')],
                        key=lambda x: int(x.split('_')[1].split('.')[0]))
    
  • 调整分片内容:如果你的"分片文件"是从同一个大docx拆分的二进制块,确保顺序即可;如果是独立docx文件,无法通过分片上传拼接成有效docx——这种情况建议直接上传多个独立文件,或放弃分片上传逻辑。

内容的提问来源于stack exchange,提问作者Akram H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:20:22