背景
环境: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模式下的进程环境变量。
明显可见两个环境的__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处理脚本代码:
/// <summary> /// 执行Python脚本 /// </summary> /// <param name="sScriptPath">脚本路径</param> /// <param name="lstParam">参数列表</param> /// <returns>是否成功</returns> public bool RunScript(string sScriptPath, List<string> 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#代码如下:
/// <summary> /// Python.exe路径在注册表中的安装位置(安装ArcGIS自带Python环境时自动创建) /// </summary> private static readonly string RegistryPythonDefaultKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\"; /// <summary> /// Python.exe路径在注册表中的键名(安装ArcGIS自带Python环境时自动创建) /// </summary> private static readonly string RegistryPythonTargetKey = "9A6767D28A88AEB44AD0AE3AA51002C0"; /// <summary> /// 获取Python.exe安装路径 /// </summary> /// <returns></returns> 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
以上这篇C#调用python.exe使用arcpy方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。
本文向大家介绍Python使用ctypes调用C/C++的方法,包括了Python使用ctypes调用C/C++的方法的使用技巧和注意事项,需要的朋友参考一下 python使用ctypes调用C/C++ 1. ctpes介绍 ctypes is a foreign function library for Python. It provides C compatible data types, a
问题内容: 我在aspx上有一个asp按钮: 如您所见,我正在调用一个使用AJAX调用C#方法的javascript函数。我这样做: 问题是,单击按钮时,我总是收到错误消息。我做错什么了吗? 编辑:C#方法。我已经设置了一个断点,以查看是否调用了该方法,但显然没有。 问题答案: 您的方法必须声明为,并用修饰。因此,您的方法应为: 编辑!!! 我看你用一些控制在你的代码(如,)。完成方法后,您将无法
从理论上说,WebService可以被任何支持SOAP协议的语言调用。在Visual Studio中使用C#调用WebService是在所有语言中最容易实现的(VB.net的调用方法类似,也同样很简单)。 新建一个Visual Studio工程,并在引用Web服务的对话框中输入如下的URL,并输入Web引用名为“WebService”: http://localhost:8080/axis2/se
问题内容: 有谁知道如何使用javascript调用服务器端c#方法?我需要做的是如果选择“取消”则停止导入,或者如果选择“确定”则继续导入。我正在使用Visual Studio 2010和C#作为编程语言 这是我的代码: 问题答案: PageMethod是Asp.Net AJAX的一种更轻松,更快速的方法。通过释放AJAX的功能,我们可以轻松地改善用户体验和Web应用程序的性能。我最喜欢AJAX
本文向大家介绍C#使用HttpPost请求调用WebService的方法,包括了C#使用HttpPost请求调用WebService的方法的使用技巧和注意事项,需要的朋友参考一下 之前调用 WebService 都是直接添加服务引用,然后调用 WebService 方法的,最近发现还可以使用 Http 请求调用 WebService。这里还想说一句,还是 web api 的调用简单。 WebSer
本文向大家介绍Objective-C语言调用方式,包括了Objective-C语言调用方式的使用技巧和注意事项,需要的朋友参考一下 示例 调用实例方法: 在当前实例上调用实例方法: 调用一个带有参数的方法: 调用类方法: