您好,登錄后才能下訂單哦!
C#中的arcpy方式怎么利用python.exe實現?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
背景
環境: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#中的arcpy方式怎么利用python.exe實現問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。