From 46c5e51772a6b371fac07ff3a61fad9f54d426f0 Mon Sep 17 00:00:00 2001 From: duxin Date: Tue, 28 Jul 2026 14:59:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20BIP=E2=86=92BSQ=20=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=A2=E5=A4=B1=E4=BF=AE=E5=A4=8D=20+=20?= =?UTF-8?q?=E5=8F=AA=E8=AF=BB=E6=96=87=E4=BB=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 延迟删除原始文件:先验证临时 BSQ 文件存在且非空,再删原始数据 - 异常处理不再删除临时 BSQ:保留完好副本供手动恢复 - 新增 _make_writable() 移除只读属性,避免 Windows PermissionError - 清理孤儿 .aux.xml 临时文件 - 路径变量提前声明,保证异常处理块可访问 --- src/core/steps/glint_removal_step.py | 74 ++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/core/steps/glint_removal_step.py b/src/core/steps/glint_removal_step.py index 25c67e1..59f578e 100644 --- a/src/core/steps/glint_removal_step.py +++ b/src/core/steps/glint_removal_step.py @@ -98,6 +98,23 @@ def _ensure_bsq(img_path): f"({_src_size/1024**3:.1f}GB, 写入临时文件后原地替换)") import time as _t _t0 = _t.time() + + # 路径变量提前声明,确保异常处理中可以访问 + _tmp_data = str(_tmp_bsq) + _tmp_hdr = _tmp_data + '.hdr' + _tmp_aux = _tmp_data + '.aux.xml' + _bip_hdr = img_path + '.hdr' + if not os.path.exists(_bip_hdr): + _bip_hdr = os.path.splitext(img_path)[0] + '.hdr' + + def _make_writable(filepath): + """去掉只读属性,避免 Windows 下 unlink/rename 拒绝访问""" + if os.path.exists(filepath): + try: + os.chmod(filepath, 0o666) + except Exception: + pass + try: from osgeo import gdal gdal.UseExceptions() @@ -108,14 +125,11 @@ def _ensure_bsq(img_path): ) _elapsed = _t.time() - _t0 - # 记录临时文件路径(后续重命名时用到) - _tmp_data = str(_tmp_bsq) - _tmp_hdr = _tmp_data + '.hdr' + # ★ 验证临时 BSQ 文件是否成功生成 + if not os.path.exists(_tmp_data) or os.path.getsize(_tmp_data) == 0: + raise RuntimeError(f"gdal.Translate 未生成有效的临时 BSQ 文件: {_tmp_data}") # ★ 保存原始 HDR 中的波长/元数据(gdal.Translate 不保留) - _bip_hdr = img_path + '.hdr' - if not os.path.exists(_bip_hdr): - _bip_hdr = os.path.splitext(img_path)[0] + '.hdr' _hdr_extras = {} # 需要保留的元数据 if os.path.exists(_bip_hdr): try: @@ -142,22 +156,36 @@ def _ensure_bsq(img_path): except Exception: pass - # 删除原始 BIP 及其 HDR - if not os.path.exists(_bip_hdr): - _bip_hdr = os.path.splitext(img_path)[0] + '.hdr' + # ★ 先处理只读属性,再删除原始 BIP 及其 HDR + _make_writable(str(_src)) + _make_writable(_bip_hdr) _src.unlink() if os.path.exists(_bip_hdr): os.unlink(_bip_hdr) # 将 BSQ 临时文件重命名为原始文件名(所有下游步骤零改动) _final = str(_src) - os.rename(_tmp_data, _final) _final_hdr = _final + '.hdr' + + # 如果目标 HDR 残留(只读等情况),先处理再删除 + _make_writable(_final_hdr) + if os.path.exists(_final_hdr): + os.unlink(_final_hdr) + + os.rename(_tmp_data, _final) if os.path.exists(_tmp_hdr): - if os.path.exists(_final_hdr): - os.unlink(_final_hdr) os.rename(_tmp_hdr, _final_hdr) + # ★ 清理孤儿 aux.xml(临时文件和可能残留的目标 aux.xml) + _final_aux = _final + '.aux.xml' + for _orphan_aux in [_tmp_aux, _final_aux]: + if os.path.exists(_orphan_aux): + try: + _make_writable(_orphan_aux) + os.unlink(_orphan_aux) + except Exception: + pass + # ★ 将波长等元数据写回新 HDR if _hdr_extras and os.path.exists(_final_hdr): try: @@ -179,14 +207,20 @@ def _ensure_bsq(img_path): f"BIP → BSQ 原地替换,所有路径无需修改") return str(_final) except Exception as e: - # 清理失败的临时文件 - if os.path.exists(_tmp_data): - try: - os.unlink(_tmp_data) - if os.path.exists(_tmp_hdr): - os.unlink(_tmp_hdr) - except Exception: - pass + # ★ 异常处理:绝不删除临时 BSQ 文件(它可能是唯一完好的数据副本) + # 如果 gdal.Translate 成功生成了临时文件,保留它供手动恢复 + if os.path.exists(_tmp_data) and os.path.getsize(_tmp_data) > 0: + print(f"[BIP→BSQ] ⚠ 转换中途失败,但临时 BSQ 文件已保留: {_tmp_data}") + print(f"[BIP→BSQ] 请手动检查该文件,确认无误后可重命名为 {img_path}") + else: + # 只有转换根本没产出时才清理(可能是磁盘满等) + for _f in [_tmp_data, _tmp_hdr, _tmp_aux]: + if os.path.exists(_f): + try: + _make_writable(_f) + os.unlink(_f) + except Exception: + pass print(f"[BIP→BSQ] 转换失败: {e},继续使用 BIP") return img_path