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

升级Windows 11后Python GIS脚本生成空Shapefile问题

问题:Win11下Python GIS脚本生成空Shapefile(原Win10稳定运行)

我有一段在Windows 10环境下长期稳定运行的Python GIS脚本,功能为提取特定坡向范围内的特定坡度区域。重装系统升级至Windows 11后,脚本运行无报错,但生成的Shapefile为空。脚本代码如下:

from os.path import join, normpath
import os, shutil
from datetime import datetime
import time
from pushbullet import Pushbullet

print("Start point:", datetime.now())

pb = Pushbullet("xx")

path_start = normpath(r'H:\GIS\worklayers0\')
path_temp = normpath(r'H:\GIS\templayers0\')
path_temp2 = normpath(r'H:\GIS\temp2layers0\')
path_end = normpath(r'H:\GIS\resultlayers0\')

slope_list = [4, 4.9, 5.9, 7.1, 8.2, 10, 11.8, 13.8, 15.7, 17.9, 20.6, 25]
aspect_list_1 = [[0, 15], [15,30], [30, 45], [45, 60], [60, 75], [75, 90], [90, 105], [105, 120], [120, 135], [135, 150], [150, 165], [165, 180]]
aspect_list_2 = [[180, 195], [195, 210], [210, 225], [225, 240], [240, 255], [255, 270], [270, 285], [285, 300], [300, 315], [315, 330], [330, 345], [345, 360]]

for filename in os.listdir(path_temp):
    file_path = os.path.join(path_temp, filename)
    try:
        if os.path.isfile(file_path) or os.path.islink(file_path):
            os.unlink(file_path)
        elif os.path.isdir(file_path):
            shutil.rmtree(file_path)
    except:
        pass

for filename in os.listdir(path_temp2):
    file_path = os.path.join(path_temp2, filename)
    try:
        if os.path.isfile(file_path) or os.path.islink(file_path):
            os.unlink(file_path)
        elif os.path.isdir(file_path):
            shutil.rmtree(file_path)
    except:
        pass
    
for filename in os.listdir(path_end):
    file_path = os.path.join(path_end, filename)
    try:
        if os.path.isfile(file_path) or os.path.islink(file_path):
            os.unlink(file_path)
        elif os.path.isdir(file_path):
            shutil.rmtree(file_path)
    except:
        pass

files = os.listdir(path_start)

for index, file in enumerate(files):
    os.rename(os.path.join(path_start, file), os.path.join(path_start, ''.join([str(index), '.tif'])))

for number in range(3):
    
    processing.run("native:slope", {'INPUT':path_start+'\\'+str(number)+'.tif','Z_FACTOR':1,'OUTPUT':path_temp+'\\'+'slope_'+str(number)+'.tif'})
    processing.run("native:aspect", {'INPUT':path_start+'\\'+str(number)+'.tif','Z_FACTOR':1,'OUTPUT':path_temp+'\\'+'aspect_'+str(number)+'.tif'})
    
    processing.run("gdal:merge", {'INPUT':[path_temp+'\\'+'aspect_'+str(number)+'.tif',path_temp+'\\'+'slope_'+str(number)+'.tif'],'PCT':True,'SEPARATE':True,'NODATA_INPUT':None,'NODATA_OUTPUT':None,'OPTIONS':'','EXTRA':'','DATA_TYPE':5,'OUTPUT':path_temp+'\\'+'merge_'+str(number)+'.tif'})
        
    processing.run("native:pixelstopolygons", {'INPUT_RASTER':path_temp+'\\'+'merge_'+str(number)+'.tif','RASTER_BAND':1,'FIELD_NAME':'ASPECT','OUTPUT':path_temp+'\\'+'aspect_'+str(number)+'.shp'})
    processing.run("native:createspatialindex", {'INPUT':path_temp+'\\'+'aspect_'+str(number)+'.shp'})
        
    processing.run("native:pixelstopolygons", {'INPUT_RASTER':path_temp+'\\'+'merge_'+str(number)+'.tif','RASTER_BAND':2,'FIELD_NAME':'SLOPE','OUTPUT':path_temp+'\\'+'slope_'+str(number)+'.shp'})
    processing.run("native:createspatialindex", {'INPUT':path_temp+'\\'+'slope_'+str(number)+'.shp'})
        
    processing.run("native:joinattributesbylocation", {'INPUT':path_temp+'\\'+'slope_'+str(number)+'.shp','PREDICATE':[5],'JOIN':path_temp+'\\'+'aspect_'+str(number)+'.shp','JOIN_FIELDS':[],'METHOD':0,'DISCARD_NONMATCHING':False,'PREFIX':'','OUTPUT':path_temp+'\\'+'aspect_slope_'+str(number)+'.shp'})
    aspect_slope_layer = iface.addVectorLayer(path_temp+'\\'+'aspect_slope_'+str(number)+'.shp', "", "ogr")
        
    
    for i in range(len(slope_list)):
        aspect_list_1[i].append(slope_list[i])
    
    for i in range(len(slope_list)):
        aspect_list_2[i].append(slope_list[::-1][i])
        
    for aspect_interval in aspect_list_1:
            start = aspect_interval[0] 
            end = aspect_interval[1]
            slope_loop = aspect_interval[2]
            aspect_slope_layer.selectByExpression('"ASPECT">'+str(start)+' and "ASPECT"<='+str(end)+' and "SLOPE">='+str(slope_loop))
            QgsVectorFileWriter.writeAsVectorFormat(aspect_slope_layer, str(path_temp)+'\\'+'aspect_slope_'+str(start)+'-'+str(end)+'_'+str(number)+'.shp', "UTF-8", aspect_slope_layer.crs(), "ESRI Shapefile", onlySelected=True)
            processing.run("native:createspatialindex", {'INPUT':str(path_temp)+'\\'+'aspect_slope_'+str(start)+'-'+str(end)+'_'+str(number)+'.shp'})
            
    for aspect_interval in aspect_list_2:
            start = aspect_interval[0] 
            end = aspect_interval[1]
            slope_loop = aspect_interval[2]
            aspect_slope_layer.selectByExpression('"ASPECT">'+str(start)+' and "ASPECT"<='+str(end)+' and "SLOPE">='+str(slope_loop))
            QgsVectorFileWriter.writeAsVectorFormat(aspect_slope_layer, str(path_temp)+'\\'+'aspect_slope_'+str(start)+'-'+str(end)+'_'+str(number)+'.shp', "UTF-8", aspect_slope_layer.crs(), "ESRI Shapefile", onlySelected=True)
            processing.run("native:createspatialindex", {'INPUT':str(path_temp)+'\\'+'aspect_slope_'+str(start)+'-'+str(end)+'_'+str(number)+'.shp'})
    
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_0-15_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_345-360_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'1_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_15-30_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_330-345_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'2_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_30-45_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_315-330_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'3_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_45-60_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_300-315_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'4_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_60-75_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_285-300_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'5_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_75-90_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_270-285_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'6_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_90-105_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_255-270_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'7_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_105-120_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_240-255_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'8_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_120-135_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_225-240_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'9_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_135-150_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_210-225_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'10_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_150-165_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_195-210_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'11_aspect_slope_int_'+str(number)+'.shp'})
    processing.run("native:mergevectorlayers", {'LAYERS':[path_temp+'\\'+'aspect_slope_165-180_'+str(number)+'.shp',path_temp+'\\'+'aspect_slope_180-195_'+str(number)+'.shp'],'CRS':None,'OUTPUT':str(path_temp2)+'\\'+'12_aspect_slope_int_'+str(number)+'.shp'})


    for i in range(1,13):
        processing.run("native:createspatialindex", {'INPUT':str(path_temp2)+'\\'+str(i)+'_aspect_slope_int_'+str(number)+'.shp'})     
    
    QgsProject.instance().removeAllMapLayers()

merge_list = os.listdir(path_temp2)

for i in range(1,13):
    check = str(i)+'_'
    name_ext_matches = []
    name_matches = [idx for idx in merge_list if idx.lower().startswith(check.lower())]
    
    for file in name_matches:
        
        if file.endswith('.shp'):
            name_ext_matches.append(file)
            
        matches = [path_temp2 +'\\'+ x for x in name_ext_matches]
            
    processing.run("native:mergevectorlayers", {'LAYERS':matches,'CRS':None,'OUTPUT':str(path_temp)+'\\'+str(i)+'_aspect_slope_int_int.shp'})
    processing.run("native:createspatialindex", {'INPUT':str(path_temp)+'\\'+str(i)+'_aspect_slope_int_int.shp'})    
    processing.run("native:refactorfields", {'INPUT':str(path_temp)+'\\'+str(i)+'_aspect_slope_int_int.shp','FIELDS_MAPPING':[{'expression': '"SLOPE"','length': 20,'name': 'SLOPE','precision': 8,'sub_type': 0,'type': 2,'type_name': 'integer'},{'expression': '"ASPECT"','length': 20,'name': 'ASPECT','precision': 8,'sub_type': 0,'type': 4,'type_name': 'int8'}],'OUTPUT':str(path_end)+'\\'+str(i)+'_aspect_slope.shp'})
    processing.run("native:createspatialindex", {'INPUT':str(path_end)+'\\'+str(i)+'_aspect_slope.shp'}) 
  
phone = pb.devices[0]
push = pb.push_note("Wakie wakie!", "All done with extracting the slopes.")
print("Notifications sent!")
print("Done!")
print("End point:", datetime.now())

排查与解决步骤

1. 修复路径与权限问题

  • Win11对文件权限管控更严格,检查H:\GIS下的临时目录(templayers0、temp2layers0、resultlayers0)是否给当前用户开放完全控制权限:右键文件夹→属性→安全选项卡配置。
  • 替换脚本中手动拼接路径的方式,统一用os.path.join()避免路径分隔符兼容性问题,示例:
    # 替换原slope工具调用代码
    processing.run("native:slope", {
        'INPUT': os.path.join(path_start, f"{number}.tif"),
        'Z_FACTOR':1,
        'OUTPUT': os.path.join(path_temp, f"slope_{number}.tif")
    })
    

2. 修正循环中列表重复修改的错误

脚本中aspect_list_1和aspect_list_2在for number in range(3):循环内重复执行append,导致第二次、第三次循环时列表长度异常,筛选条件失效。将列表修改代码移到循环外:

# 移至for number循环之前执行
for i in range(len(slope_list)):
    aspect_list_1[i].append(slope_list[i])
for i in range(len(slope_list)):
    aspect_list_2[i].append(slope_list[::-1][i])

3. 检查QGIS工具参数与版本兼容性

  • 重装系统后QGIS版本可能变更,打开Processing工具箱查看native:joinattributesbylocation的参数说明:原脚本用PREDICATE:[5](等于),像素转多边形后可能存在微小偏移,建议改为[0](相交)。
  • 替换过时的QgsVectorFileWriter.writeAsVectorFormat方法,改用兼容新版本的writeAsVectorFormatV2:
    # 替换原写入代码
    options = QgsVectorFileWriter.SaveVectorOptions()
    options.onlySelectedFeatures = True
    options.fileEncoding = "UTF-8"
    QgsVectorFileWriter.writeAsVectorFormatV2(aspect_slope_layer, 
                                              os.path.join(path_temp, f"aspect_slope_{start}-{end}_{number}.shp"),
                                              Q
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:58:10