服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#调用python.exe使用arcpy方式

C#调用python.exe使用arcpy方式

2022-10-21 13:03秋漓 C#

这篇文章主要介绍了C#调用python.exe使用arcpy方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

背景

环境: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#调用python.exe使用arcpy方式

明显可见两个环境的__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#调用python.exe使用arcpy方式

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方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_33459369/article/details/106579657

延伸 · 阅读

精彩推荐
  • C#区分WCF与WebService的异同、优势

    区分WCF与WebService的异同、优势

    这篇文章主要帮助大家区分WCF与WebService的异同、优势,分为三大方面进行研究学习,感兴趣的小伙伴们可以参考一下...

    丶一二丶8292021-11-15
  • C#Unity实现俄罗斯方块

    Unity实现俄罗斯方块

    这篇文章主要为大家详细介绍了Unity实现俄罗斯方块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两水先木示6002022-09-16
  • C#C#沉淀之委托的深入讲解

    C#沉淀之委托的深入讲解

    如果要给方法传递一个方法参数时,就可以使用委托。下面这篇文章主要给大家介绍了关于C#沉淀之委托的相关资料,文中通过示例代码介绍的非常详细,...

    东南有大树5162022-03-01
  • C#C#中将xml文件反序列化为实例时采用基类还是派生类的知识点讨论

    C#中将xml文件反序列化为实例时采用基类还是派生类的知识点讨

    在本篇文章里小编给大家整理的是关于C#中将xml文件反序列化为实例时采用基类还是派生类的知识点讨论,有需要的朋友们学习下。...

    rainbow706264652022-08-09
  • C#深入解析C#中的泛型类与泛型接口

    深入解析C#中的泛型类与泛型接口

    这篇文章主要介绍了C#中的泛型类与泛型接口,对泛型的支持是C#语言的重要特性,需要的朋友可以参考下...

    C#教程网3872021-11-11
  • C#C#访问SQLServer增删改查代码实例

    C#访问SQLServer增删改查代码实例

    这篇文章主要为大家详细介绍了C#访问SQLServer增删改查代码实例,感兴趣的小伙伴们可以参考一下...

    bcbobo21cn12082021-12-06
  • C#HttpWebRequest实现下载图片至本地

    HttpWebRequest实现下载图片至本地

    这篇文章主要为大家详细介绍了HttpWebRequest实现下载图片至本地,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    C#教程网9032022-02-27
  • C#winform实现可拖动的自定义Label控件

    winform实现可拖动的自定义Label控件

    这篇文章主要为大家详细介绍了winform实现可拖动的自定义Label控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    炒饭君10232022-02-22