C#中的arcpy方式怎么利用python.exe实现
创始人
2024-11-29 16:21:54
0次

背景

环境:ArcGis10.2.2。C#开发程序一直以来以调用Desktop的python环境(32位)来做数据处理分析。但是数据量大时,出现了内存资源不够的情况。因此决定换成使用64位python环境。

遇到问题

C#通过Process.Start()去调用64位python.exe,在Debug模式下毫无问题,但是直接运行exe就报错Process finished with exit code -1073741819 (0xC0000005)。指向异常。

分析问题

后来发现是由于arcpy模块导致的,去掉这个模块的内容就能运行,import arcpy就运行不起来。既然使用arcpy做数据处理,如果连import arcpy都不行,那还做个屁啊。于是开始寻找程序Debug模式下和Run模式下的区别。

程序中使用ProcessStartInfo类启动的python.exe的进程,那问题基本就出自这里了。附上检测代码:

var start = new ProcessStartInfo
{
 WorkingDirectory = Environment.CurrentDirectory,
 FileName = sInterpreterPath,
 UseShellExecute = false,
 ErrorDialog = true,
 CreateNoWindow = true,
 RedirectStandardOutput = true,
 RedirectStandardInput = true,
 Arguments = sParam
};
using (Process process = Process.Start(start))
{
 var a = start.Environment;
 var b = a.Keys.ToList();
 b.Sort();
 var sss = "";
 foreach (var it in b)
 {
 sss = $"{sss}\n{it}------->{a[it]}";
 }
 sss = sss.Trim();
 using (StreamReader reader = process.StandardOutput)
 {
 var sResult = "";
 while (!reader.EndOfStream)
 {
 sResult = $"{sResult} \n {reader.ReadLine()}";
 }
 sResult = sResult.Trim();
 MessageBox.Show(sResult);
 }
 MessageBox.Show("ExitCode is " + process.ExitCode);
}

于是就对比了Debug模式下与Run模式下的进程环境变量。

C#中的arcpy方式怎么利用python.exe实现

明显可见两个环境的__COMPAT_LAYER值就是不一样的。查了一下__COMPAT_LAYER是版本兼容相关参数,由于我是32位程序调用64位python.exe,因此怀疑是这个参数导致的问题。RunAsAdmin是以管理员运行,而Installer的解释是安装工具。

解决问题

上面分析出可能是__COMPAT_LAYER值不同才导致的问题,那么就能对症下药了,现在把Run下的值也设置为RunAsAdmin。加上下例代码:

start.EnvironmentVariables["__COMPAT_LAYER"] = "RunAsAdmin";

start.Environment["__COMPAT_LAYER"] = "RunAsAdmin";

再次运行,居然成功了。

下面附上C#调用64为Python.exe处理脚本代码:

/// 
/// 执行Python脚本
/// 
/// 脚本路径
/// 参数列表
/// 是否成功
public bool RunScript(string sScriptPath, List lstParam)
{
 var bResult = false;
 try
 {
 if (!File.Exists(sScriptPath))
 throw new Exception($"文件{sScriptPath}不存在!");
 var sInterpreterPath = @"E:\ArcGIS\Python27\ArcGISx6410.2\python.exe";
 var sParam = $"{sScriptPath}";
 if (null != lstParam && 0 < lstParam.Count)
 {
 var sArgument = "\"" + string.Join("\" \"", lstParam) + "\"";
 sParam = $"\"{sParam}\" {sArgument}";
 }
 var start = new ProcessStartInfo
 {
 WorkingDirectory = Environment.CurrentDirectory,
 FileName = sInterpreterPath,
 UseShellExecute = false,
 ErrorDialog = true,
 CreateNoWindow = true,
 RedirectStandardOutput = true,
 RedirectStandardInput = true,
 Arguments = sParam
 };
 start.EnvironmentVariables["__COMPAT_LAYER"] = "RunAsAdmin";
 start.Environment["__COMPAT_LAYER"] = "RunAsAdmin";
 using (Process process = Process.Start(start))
 {
 using (StreamReader reader = process.StandardOutput)
 {
 var sResult = "";
 while (!reader.EndOfStream)
 {
  sResult = $"{sResult} \n {reader.ReadLine()}";
 }
 sResult = sResult.Trim();
 MessageBox.Show(sResult);
 }
 MessageBox.Show("ExitCode is " + process.ExitCode);
 }
 }
 catch (Exception ex)
 {
 MessageBox.Show(ex.ToString());
 }
 return bResult;
}

补充知识:C#从注册表中获取ArcPy的python.exe安装位置

为何要获取该位置?

在C#中调用命令执行Python脚本的时候,Python解释器是必不可少的工具。ArcGIS 10.2.2安装时默认安装Python,但不同用户可能将Python安装到不同位置,比如,本人就将其安装到D盘而非默认的C盘。

那么,当我们的系统给其他用户使用时,势必需要找到Python解释器即python.exe文件位置,才能正常执行工具调用。

当然,你可以将文件位置写入到环境变量,这位就无需获取全路径了。本文不考虑此种情形。

如何获取该位置?

对比多台电脑发现,Python安装后,会在注册表中位置“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components”下自动创建一个键“9A6767D28A88AEB44AD0AE3AA51002C0”。

该键下有一个值,对应的数据即为python.exe的完整路径。我们只需要读到这个数据,即可获取python.exe位置。

C#中的arcpy方式怎么利用python.exe实现

C#代码如下:

  /// 
  /// Python.exe路径在注册表中的安装位置(安装ArcGIS自带Python环境时自动创建)
  /// 
  private static readonly string RegistryPythonDefaultKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\";
  /// 
  /// Python.exe路径在注册表中的键名(安装ArcGIS自带Python环境时自动创建)
  /// 
  private static readonly string RegistryPythonTargetKey = "9A6767D28A88AEB44AD0AE3AA51002C0";
  /// 
  /// 获取Python.exe安装路径
  /// 
  /// 
  private static string GetPythonPath()
  {
   var sPythonPath = "";
   try
   {
    var registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
     Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32); //判断机器位数
    var targetSubKey = registryKey.OpenSubKey(Path.Combine(RegistryPythonDefaultKey, RegistryPythonTargetKey));
    var lstName = targetSubKey.GetValueNames();
    foreach (var sName in lstName)
    {
     var sValue = targetSubKey.GetValue(sName) + string.Empty;
     if (!sValue.EndsWith("python.exe", StringComparison.OrdinalIgnoreCase) || !File.Exists(sValue))
     {
      continue;
     }
     sPythonPath = sValue;
     break;
    }
   }
   catch (Exception ex)
   {
    SysConfig.Model.LogServices.WriteExceptionLog(ex, "GetPythonPath");
   }
   return sPythonPath;
  }

需要注意的地方?

打开注册表的时候,需要判断机器位数,32位与64位注册表位置有所差异,如下:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...