# -*- coding: utf-8 -*- """ 为网页发布目录生成 STEP 压缩副档 (.step.gz),供浏览器端按需解压下载。 背景: 网页版购物车打包是逐个 fetch 原始 STEP (翻转缸单个 7-13MB), 选 20 个型号 要传 40MB+。预生成 gz 副档后前端优先取 .gz 并在浏览器解压 (DecompressionStream), 传输量降至约 1/4.5。 用法: PYTHONUTF8=1 python gen-step-gz.py # 全量生成(跳过已存在) PYTHONUTF8=1 python gen-step-gz.py --force # 强制重建 PYTHONUTF8=1 python gen-step-gz.py --clean # 删除已有 .gz 后重建 """ import os, sys, gzip, shutil, time from concurrent.futures import ThreadPoolExecutor, as_completed args = [a for a in sys.argv[1:] if not a.startswith('--')] FORCE = '--force' in sys.argv CLEAN = '--clean' in sys.argv if not args: sys.exit('用法: python gen-step-gz.py [--force|--clean]') WEB = args[0] STEP = os.path.join(WEB, 'step') if not os.path.isdir(STEP): sys.exit('找不到 ' + STEP) if CLEAN: n = 0 for f in os.listdir(STEP): if f.lower().endswith('.gz'): os.remove(os.path.join(STEP, f)) n += 1 print(f'已清理 {n} 个 .gz') files = [f for f in os.listdir(STEP) if f.lower().endswith(('.step', '.stp'))] todo = [] for f in files: src = os.path.join(STEP, f) dst = src + '.gz' if FORCE or not os.path.exists(dst): todo.append((src, dst, f)) print(f'step 文件 {len(files)} 个, 待压缩 {len(todo)} 个') def gz_one(item): src, dst, name = item tmp = dst + '.part' try: with open(src, 'rb') as fi, gzip.open(tmp, 'wb', compresslevel=6) as fo: shutil.copyfileobj(fi, fo, 1024 * 1024) os.replace(tmp, dst) return (name, os.path.getsize(src), os.path.getsize(dst), None) except Exception as e: try: os.remove(tmp) except OSError: pass return (name, 0, 0, str(e)) t0 = time.time() raw = comp = done = err = 0 errors = [] with ThreadPoolExecutor(max_workers=4) as ex: futs = [ex.submit(gz_one, it) for it in todo] for i, fut in enumerate(as_completed(futs), 1): name, r, c, e = fut.result() if e: err += 1 errors.append(f'{name}: {e}') else: done += 1 raw += r comp += c if i % 200 == 0: print(f' {i}/{len(todo)} ({time.time()-t0:.0f}s)') print(f'\n完成: {done} 个, 失败 {err} 个, 用时 {time.time()-t0:.0f}s') if raw: print(f' 原始 {raw/1073741824:.2f} GB -> gz {comp/1073741824:.2f} GB ' f'(省 {(1-comp/raw)*100:.1f}%)') for e in errors[:10]: print(' !', e) print(f'step 目录现有 .gz {sum(1 for f in os.listdir(STEP) if f.endswith(".gz"))} 个')