合并 OneDrive 上的分片文件,使用临时文件避免内存问题
(self, upload_id: str, chunk_info: UploadChunk, save_path: str)
| 782 | current_folder.upload(filename, data).execute_query() |
| 783 | |
| 784 | async def merge_chunks(self, upload_id: str, chunk_info: UploadChunk, save_path: str) -> tuple[str, str]: |
| 785 | """合并 OneDrive 上的分片文件,使用临时文件避免内存问题""" |
| 786 | file_sha256 = hashlib.sha256() |
| 787 | chunk_dir = str(Path(save_path).parent / "chunks" / upload_id) |
| 788 | |
| 789 | # 使用临时文件存储合并数据 |
| 790 | with tempfile.NamedTemporaryFile(delete=False) as temp_file: |
| 791 | temp_path = temp_file.name |
| 792 | |
| 793 | try: |
| 794 | async with aiofiles.open(temp_path, 'wb') as out_file: |
| 795 | for i in range(chunk_info.total_chunks): |
| 796 | chunk_path = f"{chunk_dir}/{i}.part" |
| 797 | chunk_record = await UploadChunk.filter(upload_id=upload_id, chunk_index=i).first() |
| 798 | if not chunk_record: |
| 799 | raise ValueError(f"分片{i}记录不存在") |
| 800 | |
| 801 | try: |
| 802 | chunk_data = await asyncio.to_thread(self._read_chunk, chunk_path) |
| 803 | except Exception as e: |
| 804 | raise ValueError(f"分片{i}文件不存在: {e}") |
| 805 | |
| 806 | current_hash = hashlib.sha256(chunk_data).hexdigest() |
| 807 | if current_hash != chunk_record.chunk_hash: |
| 808 | raise ValueError(f"分片{i}哈希不匹配: 期望 {chunk_record.chunk_hash}, 实际 {current_hash}") |
| 809 | |
| 810 | file_sha256.update(chunk_data) |
| 811 | await out_file.write(chunk_data) |
| 812 | del chunk_data # 释放内存 |
| 813 | |
| 814 | # 读取临时文件并上传 |
| 815 | async with aiofiles.open(temp_path, 'rb') as f: |
| 816 | merged_content = await f.read() |
| 817 | await asyncio.to_thread(self._upload_merged, save_path, merged_content) |
| 818 | finally: |
| 819 | # 清理临时文件 |
| 820 | if os.path.exists(temp_path): |
| 821 | os.unlink(temp_path) |
| 822 | |
| 823 | return save_path, file_sha256.hexdigest() |
| 824 | |
| 825 | def _delete_chunk_dir(self, chunk_dir: str): |
| 826 | """同步删除分片目录""" |