C#調用python.exe使用arcpy方式
背景
環(huán)境:ArcGis10.2.2。C#開發(fā)程序一直以來以調用Desktop的python環(huán)境(32位)來做數(shù)據(jù)處理分析。但是數(shù)據(jù)量大時,出現(xiàn)了內存資源不夠的情況。因此決定換成使用64位python環(huán)境。
遇到問題
C#通過Process.Start()去調用64位python.exe,在Debug模式下毫無問題,但是直接運行exe就報錯Process finished with exit code -1073741819 (0xC0000005)。指向異常。
分析問題
后來發(fā)現(xiàn)是由于arcpy模塊導致的,去掉這個模塊的內容就能運行,import arcpy就運行不起來。既然使用arcpy做數(shù)據(jù)處理,如果連import arcpy都不行,那還做個屁啊。于是開始尋找程序Debug模式下和Run模式下的區(qū)別。
程序中使用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模式下的進程環(huán)境變量。

明顯可見兩個環(huán)境的__COMPAT_LAYER值就是不一樣的。查了一下__COMPAT_LAYER是版本兼容相關參數(shù),由于我是32位程序調用64位python.exe,因此懷疑是這個參數(shù)導致的問題。RunAsAdmin是以管理員運行,而Installer的解釋是安裝工具。
解決問題
上面分析出可能是__COMPAT_LAYER值不同才導致的問題,那么就能對癥下藥了,現(xiàn)在把Run下的值也設置為RunAsAdmin。加上下例代碼:
start.EnvironmentVariables["__COMPAT_LAYER"] = "RunAsAdmin";
start.Environment["__COMPAT_LAYER"] = "RunAsAdmin";
再次運行,居然成功了。
下面附上C#調用64為Python.exe處理腳本代碼:
/// <summary>
/// 執(zhí)行Python腳本
/// </summary>
/// <param name="sScriptPath">腳本路徑</param>
/// <param name="lstParam">參數(shù)列表</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#中調用命令執(zhí)行Python腳本的時候,Python解釋器是必不可少的工具。ArcGIS 10.2.2安裝時默認安裝Python,但不同用戶可能將Python安裝到不同位置,比如,本人就將其安裝到D盤而非默認的C盤。
那么,當我們的系統(tǒng)給其他用戶使用時,勢必需要找到Python解釋器即python.exe文件位置,才能正常執(zhí)行工具調用。
當然,你可以將文件位置寫入到環(huán)境變量,這位就無需獲取全路徑了。本文不考慮此種情形。
如何獲取該位置?
對比多臺電腦發(fā)現(xiàn),Python安裝后,會在注冊表中位置“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components”下自動創(chuàng)建一個鍵“9A6767D28A88AEB44AD0AE3AA51002C0”。
該鍵下有一個值,對應的數(shù)據(jù)即為python.exe的完整路徑。我們只需要讀到這個數(shù)據(jù),即可獲取python.exe位置。

C#代碼如下:
/// <summary>
/// Python.exe路徑在注冊表中的安裝位置(安裝ArcGIS自帶Python環(huán)境時自動創(chuàng)建)
/// </summary>
private static readonly string RegistryPythonDefaultKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\";
/// <summary>
/// Python.exe路徑在注冊表中的鍵名(安裝ArcGIS自帶Python環(huán)境時自動創(chuàng)建)
/// </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); //判斷機器位數(shù)
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;
}
需要注意的地方?
打開注冊表的時候,需要判斷機器位數(shù),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方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
c#實現(xiàn)網(wǎng)站監(jiān)控查看是否正常示例
這篇文章主要介紹了使用c#監(jiān)控網(wǎng)站是否正常的功能示例,大家參考使用吧2014-01-01
C#使用StreamReader和StreamWriter類讀寫操作文件
這篇文章介紹了C#使用StreamReader和StreamWriter類讀寫操作文件的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05
WinForm使用DecExpress控件中的ChartControl插件繪制圖表
這篇文章介紹了WinForm使用DecExpress控件中的ChartControl插件繪制圖表的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05

