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模式下的进程环境变量。

明显可见两个环境的__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方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C#高性能动态获取对象属性值的步骤

    动态获取对象的性能值,这个在开发过程中经常会遇到,这里我们探讨一下何如高性能的获取属性值.为了对比测试,我们定义一个类People public class People { public string Name { get; set; } } 然后通过直接代码调用方式来取1千万次看要花多少时间: private static void Directly() { People people = new People { Name = "Wayne" }; Stopwatch stopw

  • C#窗体-数据库连接及登录功能的实现案例

    本篇文章介绍了C#窗体的数据库连接及登录功能的实现 工具或平台:VS2010.sqlserver2012 1.创建完窗体后,点击数据,选择添加新数据源 2.选择数据库 3.选择数据集 4.新建连接-Microsoft SQL Server,添加完测试一下 5.添加数据库-注意把连接字符串部分复制一下,一会儿要用的 6.保存连接字符串到配置文件中 7.选择需要用数据库的那些部分,由于我的工程较小,仅选择了表,读者根据需要自行添加 8.引入与数据库相关的命名空间(using System.Data.

  • C#获取注册表指定键值操作

    某些程序必须依赖指定运行环境.那么读取注册表来判断此电脑是否有执行环境是个很不错的办法.因为每个软件安装之后都会在注册表中注册对应的键值,并且有些键值是独一无二的. 那么首先就需要找到那个具体的独一无二的键值,以便程序在运行之前能够去读取以判断. 代码如下: class Program { private static string _sValue = string.Empty; static void Main(string[] args) { Console.WriteLine("请输入待查

  • C# 实现TXT文档转Table的示例代码

    代码: public DataTable TXTToDataTable(string fileName, string columnName) { DataTable dt = new DataTable(); FileStream fs = new FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read); StreamReader sr = new StreamReader(fs, System.Text

  • 使用C#程序验证系统登录用户与目录权限

    Windows用户类型:Administrator.Guest.自定义用户等:文件的权限不外乎:Read.Write.Modify.Remove等等,其中拥有所有权限的字符叫做FullControl. C#当前程序用户路径权限验证 /// <summary> /// 是否拥有程序数据路径权限 /// </summary> private static bool HasProgramDataRights=false; public static bool IsAdministrato

  • 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).指向异常. 分析问题 后来发现是由于arcp

  • 详解如何在VS2019和VScode中配置C++调用python接口

    why 看到这个标题有些人说了,为什么好好的C++你非要调用python?人家明明是两种语言呀! 但是在实际应用中,有时候会用到C/C++调用python来更简单地去完成一些功能,不然人家python为什么有一个文件夹叫include,里边全是.h文件呢? VScode中配置环境 首先是在VScode中为C++调用python接口配置环境,这里假设你已经配置好了c++编程环境! 1.配置step1 用快捷键Ctrl+Shift+X打开Extensions 商店,输入python,install:

  • C#调用Python程序传参数获得返回值

    目录 说明 1. Python 脚本 2. 打包成Windows可执行文件 3. C# 程序 4. 参考 说明 C# 调用 Python 程序有多种方式,本篇用的是第 4 种: nuget的ironPython: 用 c/c++ 调用python,再封装成库文件,c# 调用: c# 命令行调用.py文件执行: python 程序制作成 .exe 可执行文件,c# 使用命令行进行传参取返回值. 1. Python 脚本 先建个测试脚本 d://Test/EchoHi.py 代码如下: import

  • 在python中实现调用可执行文件.exe的3种方法

    方法一. os.system() 会保存可执行程序中的打印值和主函数的返回值,且会将执行过程中要打印的内容打印出来 import os main = "project1.exe" r_v = os.system(main) print (r_v ) 方法二. commands.getstatusoutput() 会保存可执行程序中的打印值和主函数的返回值,但不会将执行过程中要打印的内容打印出来 import subprocess import os main = "proje

  • python调用接口的4种方式代码实例

    这篇文章主要介绍了python调用接口的4种方式代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 python中调用API的几种方式: - urllib2 - httplib2 - pycurl - requests 1.urllib2 import urllib2, urllib github_url = 'https://api.github.com/user/repos' password_manager = urllib2.HTT

  • Python如何在main中调用函数内的函数方式

    一般在Python中在函数中定义的函数是不能直接调用的,但是如果要用的话怎么办呢? 一般情况下: def a():#第一层函数 def b():#第二层函数 print('打开文件B') b()#第二层中的函数直接调用 结果显示: Traceback (most recent call last): File "C:/Users/rog/Desktop/wenzhang.py", line 4, in <module> b() NameError: name 'b' is

  • python 调用js的四种方式

    1. 前言 日常 Web 端爬虫过程中,经常会遇到参数被加密的场景,因此,我们需要分析网页源代码 通过调式,一层层剥离出关键的 JS 代码,使用 Python 去执行这段代码,得出参数加密前后的 Python 实现 本文将聊聊利用 Python 调用 JS 的4种方式 2. 准备 以一段简单的 JS 脚本为例,将代码写入到文件中 //norm.js //计算两个数的和 function add(num1, num2) {     return num1 + num2; } 其中,定义了一个方法,

  • 利用Hyperic调用Python实现进程守护

    利用Hyperic调用Python,实现进程守护,供大家参考,具体内容如下 调用操作系统方法获取进程信息,判断进程是否存在,Linux和Windows均支持,区别在于获取进程信息和启动进程的方法不同. 代码如下: #!/usr/bin/python #-*- coding:utf-8 -*- """ 名称:进程检查脚本 作者:wjzhu 时间:2014-06-30 功能:根据进程名称,判断进程是否存在,执行相应操作 参数:p_name:进程名称|p_path:进程启动路径 返

  • C#调用python脚本的方法步骤(2种)

    因项目需要,需要使用C#控制台程序执行python脚本,查询各种资料后可以成功调用了,记录一下,以备后面遗忘. 只尝试了两种调用方式,第一种只适用于python脚本中不包含第三方模块的情况,第二种针对的是python脚本中包含第三方模块的情况.不管哪种方式,首先都需要安装IronPython.我是通过vs2017的工具->NuGet包管理器->管理解决方案的NuGet包,搜索IronPython包安装,也可以在官网下载安装包自行安装后添加引用即可. 方式一:适用于python脚本中不包含第三方

  • 详解如何在Java中调用Python程序

    Java中调用Python程序 1.新建一个Maven工程,导入如下依赖 <dependency> <groupId>org.python</groupId> <artifactId>jython-standalone</artifactId> <version>2.7.0</version> </dependency> 2.在java中直接执行python代码片段 import org.python.util

随机推荐